Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
Sam Therapy | 1e528c3144 |
21
.drone.yml
21
.drone.yml
|
@ -1,8 +1,13 @@
|
|||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
steps:
|
||||
- name: test
|
||||
image: golang
|
||||
commands:
|
||||
- go test ./...
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: default
|
||||
steps:
|
||||
- name: lint
|
||||
image: denoland/deno:debian
|
||||
commands:
|
||||
- deno fmt --check
|
||||
- deno lint
|
||||
- name: test
|
||||
image: denoland/deno:debian
|
||||
commands:
|
||||
- deno test -A
|
154
.gitignore
vendored
154
.gitignore
vendored
|
@ -1,18 +1,136 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
# ---> Node
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
.dccache
|
||||
|
||||
result.json
|
||||
*.vtt
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"deno.enable": true,
|
||||
"deno.lint": true,
|
||||
"deno.unstable": true
|
||||
}
|
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.
|
5
LICENSE
Normal file
5
LICENSE
Normal file
|
@ -0,0 +1,5 @@
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
39
README.md
39
README.md
|
@ -1,35 +1,4 @@
|
|||
# awl
|
||||
|
||||
`awl` is a command-line DNS client, much like
|
||||
[`drill`](https://github.com/NLnetLabs/ldns),
|
||||
[`dig`](https://bind9.readthedocs.io/en/v9_18_3/manpages.html#dig-dns-lookup-utility),
|
||||
[`dog`](https://github.com/ogham/dog),
|
||||
[`doggo`](https://github.com/mr-karan/doggo),
|
||||
or [`q`](https://github.com/natesales/q)
|
||||
|
||||
This was made as my first major experiment with Go, so there are probably things that can be improved
|
||||
|
||||
The excellent [dns](https://github.com/miekg/dns) library for Go does most of the heavy
|
||||
lifting.
|
||||
|
||||
## What works
|
||||
|
||||
- UDP
|
||||
- TCP
|
||||
- TLS
|
||||
- HTTPS (maybe)
|
||||
- QUIC (extreme maybe)
|
||||
|
||||
## What doesn't
|
||||
|
||||
- Your sanity after reading my awful code
|
||||
- A motivation for making this after finding q and doggo
|
||||
|
||||
## What should change
|
||||
|
||||
- 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?
|
||||
# awl: drill, writ small (and using deno)
|
||||
|
||||
Install:
|
||||
`deno install --allow-net https://git.froth.zone/sam/awl/raw/branch/master/awl.ts`
|
||||
|
|
53
args.ts
Normal file
53
args.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { Args } from "./deps.ts";
|
||||
import { isRecordType, ServerOptions } from "./lib/utils.ts";
|
||||
/**
|
||||
* A handler for parsing the arguments passed in
|
||||
* @param {ServerOptions} server - The DNS server to query
|
||||
* @param {Deno.RecordType} type - The type of DNS request, see Deno.RecordType for more info
|
||||
* @param {string} name - Server to look up
|
||||
*/
|
||||
export type arguments = {
|
||||
server?: ServerOptions;
|
||||
type?: Deno.RecordType;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Args} args - The arguments, directly passed in
|
||||
* @returns {arguments} The arguments, parsed
|
||||
*/
|
||||
export function parseArgs(args: Args): arguments {
|
||||
const parsed: arguments = {} as arguments;
|
||||
args._.forEach((arg) => {
|
||||
arg = arg.toString();
|
||||
|
||||
// if it starts with an @, it's a server
|
||||
if (arg.includes("@")) {
|
||||
parsed.server = {
|
||||
server: arg.split("@").pop() as string,
|
||||
port: args.port,
|
||||
};
|
||||
return;
|
||||
}
|
||||
// if there is a dot, it's a name
|
||||
if (arg.includes(".")) {
|
||||
parsed.name = arg;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRecordType(arg)) {
|
||||
parsed.type = arg.toUpperCase() as Deno.RecordType;
|
||||
return;
|
||||
}
|
||||
|
||||
// if all else fails, assume it's a name
|
||||
parsed.name = arg;
|
||||
});
|
||||
|
||||
// Add a . to the end of the name if it's not there
|
||||
if (parsed.name?.charAt(parsed.name.length - 1) !== ".") {
|
||||
parsed.name = parsed.name?.concat(".");
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
17
awl.go
17
awl.go
|
@ -1,17 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := prepareCLI()
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
200
cli.go
200
cli.go
|
@ -1,200 +0,0 @@
|
|||
// 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
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)
|
||||
}
|
||||
}
|
7
deps.ts
Normal file
7
deps.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export { parse } from "https://deno.land/std@0.144.0/flags/mod.ts";
|
||||
export type { Args } from "https://deno.land/std@0.144.0/flags/mod.ts";
|
||||
export {
|
||||
bold,
|
||||
italic,
|
||||
underline,
|
||||
} from "https://deno.land/std@0.139.0/fmt/colors.ts";
|
12
docs.go
12
docs.go
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
awl is a DNS lookup tool written in Go,
|
||||
similar to (and heavily inspired by) drill.
|
||||
|
||||
It runs and displays similar outputs to drill, without any frills.
|
||||
Options are given to print with JSON
|
||||
|
||||
Supports results from DNS-over-[UDP, TCP, TLS, HTTPS, QUIC] servers
|
||||
|
||||
Why use this over the alternatives? Good question.
|
||||
*/
|
||||
package main
|
37
go.mod
37
go.mod
|
@ -1,37 +0,0 @@
|
|||
module git.froth.zone/sam/awl
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
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/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/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // 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-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
|
||||
)
|
312
go.sum
312
go.sum
|
@ -1,312 +0,0 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
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/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/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=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
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/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=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
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=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.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/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=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
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/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=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
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/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/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/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=
|
||||
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=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-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/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=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-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/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=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-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/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=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
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=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
65
lib/query.ts
Normal file
65
lib/query.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
import { QueryResponse, ServerOptions } from "./utils.ts";
|
||||
|
||||
/**
|
||||
* @param domain Domain to query
|
||||
* @param query
|
||||
* @param server {@link utils.ts/ServerOptions}
|
||||
* @returns
|
||||
*/
|
||||
export async function doQuery(
|
||||
domain: string,
|
||||
query: Deno.RecordType,
|
||||
server?: ServerOptions,
|
||||
) {
|
||||
const response: QueryResponse = {} as QueryResponse;
|
||||
if (!server?.server) {
|
||||
const t0 = performance.now();
|
||||
await Deno.resolveDns(domain, query)
|
||||
// If there's no error
|
||||
.then((value) => {
|
||||
const t1 = performance.now();
|
||||
response.time = t1 - t0;
|
||||
response.response = "NOERROR";
|
||||
response.dnsResponse = value;
|
||||
})
|
||||
// If there is an error
|
||||
.catch((e: Error) => {
|
||||
const t1 = performance.now();
|
||||
response.time = t1 - t0;
|
||||
switch (e.name) {
|
||||
case "NotFound":
|
||||
response.response = "NXDOMAIN";
|
||||
break;
|
||||
default:
|
||||
console.dir(e);
|
||||
response.response = "SERVFAIL";
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const t0 = performance.now();
|
||||
await Deno.resolveDns(domain, query, {
|
||||
nameServer: { "ipAddr": server.server, "port": server.port },
|
||||
})
|
||||
// If there's no error
|
||||
.then((value) => {
|
||||
const t1 = performance.now();
|
||||
response.time = t1 - t0;
|
||||
response.response = "NOERROR";
|
||||
response.dnsResponse = value;
|
||||
})
|
||||
// If there is an error
|
||||
.catch((e: Error) => {
|
||||
const t1 = performance.now();
|
||||
response.time = t1 - t0;
|
||||
switch (e.name) {
|
||||
case "NotFound":
|
||||
response.response = "NXDOMAIN";
|
||||
break;
|
||||
default:
|
||||
response.response = "SERVFAIL";
|
||||
}
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
117
lib/response.ts
Normal file
117
lib/response.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
import {
|
||||
isCAA,
|
||||
isMX,
|
||||
isNAPTR,
|
||||
isSOA,
|
||||
isSRV,
|
||||
isTXT,
|
||||
QueryResponse,
|
||||
} from "./utils.ts";
|
||||
|
||||
/**
|
||||
* @param res A DNS {@link QueryResponse}
|
||||
* @param domain The domain (or IP, if doing it in reverse) queried
|
||||
* @param query The DNS query that was queried
|
||||
* @returns {string} The DNS response, put in canonical form
|
||||
*/
|
||||
export function parseResponse(
|
||||
res: QueryResponse,
|
||||
domain: string,
|
||||
query: string,
|
||||
short: boolean,
|
||||
): string[] {
|
||||
const answer: string[] = [];
|
||||
switch (query) {
|
||||
case "A":
|
||||
case "AAAA":
|
||||
case "CNAME":
|
||||
case "NS":
|
||||
case "PTR":
|
||||
res.dnsResponse.forEach((ip) => {
|
||||
let dnsQuery = "";
|
||||
if (!short) dnsQuery += `${domain} IN ${query} `;
|
||||
dnsQuery += `${ip}`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
break;
|
||||
case "MX":
|
||||
if (isMX(res.dnsResponse)) {
|
||||
res.dnsResponse.forEach((record) => {
|
||||
let dnsQuery = "";
|
||||
if (!short) {
|
||||
dnsQuery += `${domain} IN ${query} `;
|
||||
}
|
||||
dnsQuery += `${record.preference} ${record.exchange}`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "CAA":
|
||||
if (isCAA(res.dnsResponse)) {
|
||||
res.dnsResponse.forEach((record) => {
|
||||
let dnsQuery = "";
|
||||
if (!short) {
|
||||
dnsQuery += `${domain} IN ${query} `;
|
||||
}
|
||||
dnsQuery += `${
|
||||
record.critical ? "1" : "0"
|
||||
} ${record.tag} "${record.value}"`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "NAPTR":
|
||||
if (isNAPTR(res.dnsResponse)) {
|
||||
res.dnsResponse.forEach((record) => {
|
||||
let dnsQuery = "";
|
||||
if (!short) dnsQuery += `${domain} IN ${query} `;
|
||||
dnsQuery +=
|
||||
`${record.order} ${record.preference} "${record.flags}" "${record.services}" ${record.regexp} ${record.replacement}`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "SOA":
|
||||
if (isSOA(res.dnsResponse)) {
|
||||
res.dnsResponse.forEach((record) => {
|
||||
let dnsQuery = "";
|
||||
if (!short) dnsQuery += `${domain} IN ${query} `;
|
||||
dnsQuery +=
|
||||
`${record.mname} ${record.rname} ${record.serial} ${record.refresh} ${record.retry} ${record.expire} ${record.minimum}`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "SRV":
|
||||
if (isSRV(res.dnsResponse)) {
|
||||
res.dnsResponse.forEach((record) => {
|
||||
let dnsQuery = "";
|
||||
if (!short) dnsQuery += `${domain} IN ${query} `;
|
||||
dnsQuery +=
|
||||
`${record.priority} ${record.weight} ${record.port} ${record.target}`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "TXT":
|
||||
if (isTXT(res.dnsResponse)) {
|
||||
res.dnsResponse.forEach((record) => {
|
||||
let dnsQuery = "";
|
||||
let txt = "";
|
||||
record.forEach((value) => {
|
||||
txt += `"${value}"`;
|
||||
});
|
||||
if (!short) {
|
||||
dnsQuery += `${domain} IN ${query} `;
|
||||
}
|
||||
dnsQuery += `${txt}`;
|
||||
answer.push(dnsQuery);
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Not yet implemented");
|
||||
}
|
||||
return answer;
|
||||
}
|
73
lib/reverse.ts
Normal file
73
lib/reverse.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
export function parsePTR(ip: string) {
|
||||
if (ip.includes(".")) {
|
||||
// It's an IPv4 address
|
||||
const ptr = ip.split(".");
|
||||
let pop: string | undefined = "not undefined";
|
||||
let domain = "";
|
||||
do {
|
||||
pop = ptr.pop();
|
||||
if (pop) {
|
||||
domain += `${pop}.`;
|
||||
}
|
||||
} while (pop !== undefined);
|
||||
domain += "in-addr.arpa";
|
||||
return domain;
|
||||
} else if (ip.includes(":")) {
|
||||
const parsedIP = parseIPv6(ip);
|
||||
const ptr = parsedIP.split(":");
|
||||
// It's an IPv6 address
|
||||
let pop: string[] | undefined = ["e"];
|
||||
let domain = "";
|
||||
do {
|
||||
pop = ptr.pop()?.split("").reverse();
|
||||
if (pop) {
|
||||
for (const part of pop) {
|
||||
domain += `${part}.`;
|
||||
}
|
||||
}
|
||||
} while (pop !== undefined);
|
||||
domain += "ip6.arpa";
|
||||
return domain;
|
||||
} else {
|
||||
// It's not an address
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
export function parseIPv6(addr: string) {
|
||||
addr = addr.replace(/^:|:$/g, "");
|
||||
|
||||
const ipv6 = addr.split(":");
|
||||
|
||||
for (let i = 0; i < ipv6.length; i++) {
|
||||
let hex: string | string[] = ipv6[i];
|
||||
if (hex != "") {
|
||||
// normalize leading zeros
|
||||
// TODO: make this not deprecated
|
||||
ipv6[i] = ("0000" + hex).substr(-4);
|
||||
} else {
|
||||
// normalize grouped zeros ::
|
||||
hex = [];
|
||||
for (let j = ipv6.length; j <= 8; j++) {
|
||||
hex.push("0000");
|
||||
}
|
||||
ipv6[i] = hex.join(":");
|
||||
}
|
||||
}
|
||||
|
||||
return ipv6.join(":");
|
||||
}
|
||||
|
||||
export function parseNAPTR(phNum: string) {
|
||||
phNum = phNum.toString();
|
||||
phNum = phNum.replace("+", "").replaceAll(" ", "").replaceAll("-", "");
|
||||
const rev = phNum.split("").reverse();
|
||||
let ptr = "";
|
||||
rev.forEach((n) => {
|
||||
ptr += `${n}.`;
|
||||
});
|
||||
ptr += "e164.arpa";
|
||||
return ptr;
|
||||
}
|
93
lib/utils.ts
Normal file
93
lib/utils.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* A DNS response
|
||||
*/
|
||||
export type QueryResponse = {
|
||||
dnsResponse:
|
||||
| string[]
|
||||
| Deno.CAARecord[]
|
||||
| Deno.MXRecord[]
|
||||
| Deno.NAPTRRecord[]
|
||||
| Deno.SOARecord[]
|
||||
| Deno.SRVRecord[]
|
||||
| string[][];
|
||||
response: string;
|
||||
time: number;
|
||||
};
|
||||
/**
|
||||
* Options for which DNS server to query
|
||||
*/
|
||||
export type ServerOptions = {
|
||||
server: string;
|
||||
port?: number;
|
||||
};
|
||||
|
||||
export function isRecordType(type: string): type is Deno.RecordType {
|
||||
return type.toUpperCase() === "A" || type.toUpperCase() === "AAAA" ||
|
||||
type.toUpperCase() === "CNAME" || type.toUpperCase() === "MX" ||
|
||||
type.toUpperCase() === "NS" || type.toUpperCase() === "PTR" ||
|
||||
type.toUpperCase() === "SOA" || type.toUpperCase() === "TXT" ||
|
||||
type.toUpperCase() === "NAPTR" || type.toUpperCase() === "SRV" ||
|
||||
type.toUpperCase() === "CAA";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the DNS query is an MX record
|
||||
* @param {QueryResponse["dnsResponse"]} record - DNS response
|
||||
* @returns {boolean} - true if the record is an MX record
|
||||
*/
|
||||
export function isMX(
|
||||
record: QueryResponse["dnsResponse"],
|
||||
): record is Deno.MXRecord[] {
|
||||
return (record as unknown as Deno.MXRecord[])[0].exchange !== undefined;
|
||||
}
|
||||
/**
|
||||
* Test if the DNS query is a CAA record
|
||||
* @param {QueryResponse["dnsResponse"]} record - DNS response
|
||||
* @returns {boolean} - true if the record is a CAA record
|
||||
*/
|
||||
export function isCAA(
|
||||
record: QueryResponse["dnsResponse"],
|
||||
): record is Deno.CAARecord[] {
|
||||
return (record as unknown as Deno.CAARecord[])[0].critical !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the DNS query is an NAPTR record
|
||||
* @param {QueryResponse["dnsResponse"]} record - DNS response
|
||||
* @returns {boolean} - true if the record is an NAPTR record
|
||||
*/
|
||||
export function isNAPTR(
|
||||
record: QueryResponse["dnsResponse"],
|
||||
): record is Deno.NAPTRRecord[] {
|
||||
return (record as unknown as Deno.NAPTRRecord[])[0].regexp !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the DNS query is an SOA record
|
||||
* @param {QueryResponse["dnsResponse"]} record - DNS response
|
||||
* @returns {boolean} - true if the record is an SOA record
|
||||
*/
|
||||
export function isSOA(
|
||||
record: QueryResponse["dnsResponse"],
|
||||
): record is Deno.SOARecord[] {
|
||||
return (record as unknown as Deno.SOARecord[])[0].rname !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the DNS query is an SRV record
|
||||
* @param {QueryResponse["dnsResponse"]} record - DNS response
|
||||
* @returns {boolean} - true if the record is an SRV record
|
||||
*/
|
||||
export function isSRV(
|
||||
record: QueryResponse["dnsResponse"],
|
||||
): record is Deno.SRVRecord[] {
|
||||
return (record as unknown as Deno.SRVRecord[])[0].port !== undefined;
|
||||
}
|
||||
|
||||
export function isTXT(
|
||||
record: QueryResponse["dnsResponse"],
|
||||
): record is string[][] {
|
||||
return Array.isArray(record as unknown as Array<string>);
|
||||
}
|
|
@ -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...)
|
||||
}
|
8
mod.ts
Normal file
8
mod.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Exports for lawl, the library for awl
|
||||
export type { QueryResponse, ServerOptions } from "./lib/utils.ts";
|
||||
export { isRecordType } from "./lib/utils.ts";
|
||||
export { doQuery } from "./lib/query.ts";
|
||||
export { parseResponse } from "./lib/response.ts";
|
||||
export { parseIPv6, parseNAPTR, parsePTR } from "./lib/reverse.ts";
|
186
query.go
186
query.go
|
@ -1,186 +0,0 @@
|
|||
// 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
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
// 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
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// 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
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
// Package for the special query types
|
||||
package query
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
":npm",
|
||||
":gomod"
|
||||
]
|
||||
}
|
59
tests/query_test.ts
Normal file
59
tests/query_test.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
import { assertEquals } from "./testDeps.ts";
|
||||
import { doQuery } from "../lib/query.ts";
|
||||
|
||||
Deno.test("Get localhost", async () => {
|
||||
const res = await doQuery("localhost", "A");
|
||||
assertEquals(res.dnsResponse, ["127.0.0.1"]);
|
||||
assertEquals(res.response, "NOERROR");
|
||||
});
|
||||
|
||||
Deno.test("Get localhost, external NS", async () => {
|
||||
const res = await doQuery("localhost", "AAAA", { server: "1.1.1.1" });
|
||||
assertEquals(res.dnsResponse, ["::1"]);
|
||||
assertEquals(res.response, "NOERROR");
|
||||
});
|
||||
|
||||
Deno.test("PTR localhost", async () => {
|
||||
const res = await doQuery("1.0.0.127.in-addr.arpa.", "PTR");
|
||||
assertEquals(res.dnsResponse, ["localhost."]);
|
||||
});
|
||||
|
||||
// This test will fail if this random Bri ish phone number goes down
|
||||
// It's also unreliable, so it's disabled
|
||||
// Deno.test("NAPTR, Remote",async () => {
|
||||
// const res = await doQuery("4.4.2.2.3.3.5.6.8.1.4.4.e164.arpa.", "NAPTR");
|
||||
// assertStrictEquals(res.dnsResponse, [
|
||||
// {
|
||||
// order: 100,
|
||||
// preference: 10,
|
||||
// flags: "u",
|
||||
// services: "E2U+sip",
|
||||
// regexp: "!^\\+441865332(.*)$!sip:\\1@nominet.org.uk!",
|
||||
// replacement: "."
|
||||
// },
|
||||
// {
|
||||
// order: 100,
|
||||
// preference: 20,
|
||||
// flags: "u",
|
||||
// services: "E2U+pstn:tel",
|
||||
// regexp: "!^(.*)$!tel:\\1!",
|
||||
// replacement: "."
|
||||
// }
|
||||
// ])
|
||||
// })
|
||||
|
||||
Deno.test("Get invalid IP, regular NS", async () => {
|
||||
const res = await doQuery("l", "A");
|
||||
assertEquals(res.dnsResponse, undefined);
|
||||
assertEquals(res.response, "NXDOMAIN");
|
||||
});
|
||||
|
||||
// This isn't supposed to SERVFAIL
|
||||
// It also takes forever
|
||||
|
||||
Deno.test("Get invalid IP, external NS", async () => {
|
||||
const res = await doQuery("b", "AAAA", { server: "1.1.1.1" });
|
||||
assertEquals(res.dnsResponse, undefined);
|
||||
assertEquals(res.response, "SERVFAIL");
|
||||
});
|
112
tests/response_test.ts
Normal file
112
tests/response_test.ts
Normal file
|
@ -0,0 +1,112 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
import { assertEquals, assertThrows } from "./testDeps.ts";
|
||||
import { parseResponse } from "../lib/response.ts";
|
||||
import { QueryResponse } from "../lib/utils.ts";
|
||||
|
||||
const mockResponse: QueryResponse = {
|
||||
dnsResponse: [],
|
||||
response: "NOERROR",
|
||||
time: 0,
|
||||
};
|
||||
let domain = "localhost.";
|
||||
|
||||
Deno.test("A query", () => {
|
||||
mockResponse.dnsResponse = ["127.0.0.1"];
|
||||
assertEquals(parseResponse(mockResponse, domain, "A", false), [
|
||||
"localhost. IN A 127.0.0.1",
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("AAAA query, short", () => {
|
||||
mockResponse.dnsResponse = ["::1"];
|
||||
assertEquals(parseResponse(mockResponse, domain, "AAAA", true), [
|
||||
"::1",
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("MX query", () => {
|
||||
mockResponse.dnsResponse = [{
|
||||
exchange: "mail.localhost",
|
||||
preference: 10,
|
||||
}];
|
||||
assertEquals(parseResponse(mockResponse, domain, "MX", false), [
|
||||
"localhost. IN MX 10 mail.localhost",
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("CAA query", () => {
|
||||
mockResponse.dnsResponse = [{
|
||||
critical: false,
|
||||
tag: "issue",
|
||||
value: "pki.goog",
|
||||
}];
|
||||
assertEquals(parseResponse(mockResponse, domain, "CAA", false), [
|
||||
'localhost. IN CAA 0 issue "pki.goog"',
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("NAPTR query", () => {
|
||||
domain = "4.3.2.1.5.5.5.0.0.8.1.e164.arpa.";
|
||||
mockResponse.dnsResponse = [{
|
||||
flags: "u",
|
||||
order: 100,
|
||||
preference: 10,
|
||||
services: "E2U+sip",
|
||||
regexp: "!^.*$!sip:customer-service@example.com!",
|
||||
replacement: ".",
|
||||
}, {
|
||||
flags: "u",
|
||||
order: 102,
|
||||
preference: 10,
|
||||
services: "E2U+email",
|
||||
regexp: "!^.*$!mailto:information@example.com!",
|
||||
replacement: ".",
|
||||
}];
|
||||
assertEquals(parseResponse(mockResponse, domain, "NAPTR", false), [
|
||||
`4.3.2.1.5.5.5.0.0.8.1.e164.arpa. IN NAPTR 100 10 "u" "E2U+sip" !^.*$!sip:customer-service@example.com! .`,
|
||||
`4.3.2.1.5.5.5.0.0.8.1.e164.arpa. IN NAPTR 102 10 "u" "E2U+email" !^.*$!mailto:information@example.com! .`,
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("SOA query", () => {
|
||||
domain = "cloudflare.com.";
|
||||
mockResponse.dnsResponse = [{
|
||||
mname: "ns3.cloudflare.com.",
|
||||
rname: "dns.cloudflare.com.",
|
||||
serial: 2280958559,
|
||||
refresh: 10000,
|
||||
retry: 2400,
|
||||
expire: 604800,
|
||||
minimum: 300,
|
||||
}];
|
||||
assertEquals(parseResponse(mockResponse, domain, "SOA", false), [
|
||||
"cloudflare.com. IN SOA ns3.cloudflare.com. dns.cloudflare.com. 2280958559 10000 2400 604800 300",
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("SRV query", () => {
|
||||
domain = "localhost";
|
||||
mockResponse.dnsResponse = [{
|
||||
port: 22,
|
||||
priority: 0,
|
||||
target: "localhost",
|
||||
weight: 10,
|
||||
}];
|
||||
assertEquals(parseResponse(mockResponse, domain, "SRV", false), [
|
||||
"localhost IN SRV 0 10 22 localhost",
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("TXT query", () => {
|
||||
mockResponse.dnsResponse = [["a"]];
|
||||
assertEquals(parseResponse(mockResponse, domain, "TXT", false), [
|
||||
'localhost IN TXT "a"',
|
||||
]);
|
||||
});
|
||||
|
||||
Deno.test("Invalid query", () => {
|
||||
mockResponse.dnsResponse = [["a"]];
|
||||
assertThrows((): void => {
|
||||
parseResponse(mockResponse, domain, "E", true);
|
||||
});
|
||||
});
|
43
tests/reverse_test.ts
Normal file
43
tests/reverse_test.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
import { parseIPv6, parseNAPTR, parsePTR } from "../lib/reverse.ts";
|
||||
import { assertEquals } from "./testDeps.ts";
|
||||
|
||||
Deno.test("IPv6 Parse, localhost", () => {
|
||||
assertEquals(parseIPv6("::1"), "0000:0000:0000:0000:0000:0000:0000:0001");
|
||||
});
|
||||
|
||||
Deno.test("IPv6 Parse, :: in middle of address", () => {
|
||||
assertEquals(
|
||||
parseIPv6("2001:4860:4860::8844"),
|
||||
"2001:4860:4860:0000:0000:0000:0000:8844",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("IPv4 PTR, localhost", () => {
|
||||
assertEquals(parsePTR("127.0.0.1"), "1.0.0.127.in-addr.arpa");
|
||||
});
|
||||
|
||||
Deno.test("IPv6 PTR, actual IP", () => {
|
||||
assertEquals(
|
||||
parsePTR("2606:4700:4700::1111"),
|
||||
"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",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("PTR, Fallback lel", () => {
|
||||
assertEquals(parsePTR("1367218g3a1"), "");
|
||||
});
|
||||
|
||||
Deno.test("NAPTR, US number", () => {
|
||||
assertEquals(
|
||||
parseNAPTR("+1-800-555-1234"),
|
||||
"4.3.2.1.5.5.5.0.0.8.1.e164.arpa",
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("NAPTR, non-US number", () => {
|
||||
assertEquals(
|
||||
parseNAPTR("44 186 533 2244"),
|
||||
"4.4.2.2.3.3.5.6.8.1.4.4.e164.arpa",
|
||||
);
|
||||
});
|
4
tests/testDeps.ts
Normal file
4
tests/testDeps.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export {
|
||||
assertEquals,
|
||||
assertThrows,
|
||||
} from "https://deno.land/std@0.144.0/testing/asserts.ts";
|
|
@ -1,2 +0,0 @@
|
|||
// Helper functions
|
||||
package util
|
|
@ -1,57 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type Response struct {
|
||||
Answers Answers `json:"Response"` // These be DNS query answers
|
||||
}
|
||||
|
||||
// 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"` // The time it took to make the DNS query
|
||||
}
|
||||
|
||||
// Given an IP or phone number, return a canonical string to be queried
|
||||
func ReverseDNS(address string, query string) (string, error) {
|
||||
if query == "PTR" {
|
||||
return dns.ReverseAddr(address)
|
||||
} else if query == "NAPTR" {
|
||||
// get rid of characters not needed
|
||||
replacer := strings.NewReplacer("+", "", " ", "", "-", "")
|
||||
address = replacer.Replace(address)
|
||||
// reverse the order of the string
|
||||
address = reverse(address)
|
||||
var arpa strings.Builder
|
||||
// Make it canonical
|
||||
for _, c := range address {
|
||||
fmt.Fprintf(&arpa, "%c.", c)
|
||||
}
|
||||
arpa.WriteString("e164.arpa.")
|
||||
return arpa.String(), nil
|
||||
}
|
||||
|
||||
return "", errors.New("ReverseDNS: -x flag given but no IP found")
|
||||
}
|
||||
|
||||
// Reverse a string, return the string in reverse
|
||||
func reverse(s string) string {
|
||||
rns := []rune(s)
|
||||
for i, j := 0, len(rns)-1; i < j; i, j = i+1, j-1 {
|
||||
|
||||
rns[i], rns[j] = rns[j], rns[i]
|
||||
}
|
||||
return string(rns)
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
// 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)
|
||||
}
|
Loading…
Reference in a new issue