Compare commits

...

69 commits
v0.3.0 ... main

Author SHA1 Message Date
astra
db8c7ef8eb Change primary color 2023-03-26 23:58:57 +01:00
astra
1aea2d35a5 Add dark theme 2023-03-26 23:34:06 +01:00
astra
6b9bd48e60 Update import path and dependencies 2023-03-26 23:33:20 +01:00
Karan Sharma
8492ccdc61 chore: build for go 1.19
Closes https://github.com/mr-karan/doggo/issues/62
2023-01-03 17:15:38 +05:30
Maximilian Bosch
88c63d6b41 Support literal IPv6 nameservers
This effectively means that `doggo @2001:DB8::53 example.org` works just
like we know it from `dig(1)`. This already works for IPv4 because
`url.Parse` accepts a literal IPv4 address, but not a literal IPv6
address (due to parsing ambiguities with strings that look like an IPv4
address I guess).

This is implemented by checking if the nameserver argument is a valid IP
if the URL validation failed. If that's the case, `ns` is returned
directly with the `[2001:DB8::53]:53` as address (from
`net.JoinHostPort` with the default DNS port) and UDP as protocol (also
the default if not specified).
2022-12-14 11:29:55 +05:30
Aliaksandr Belik
c21f90c2bc docs: add scoop installation note
Fixes #36.
2022-11-08 10:43:52 +05:30
Karan Sharma
3409971103 chore: fix typo in nameserver flag
Closes https://github.com/mr-karan/doggo/issues/55
2022-10-24 11:14:18 +05:30
Sheogorath
9386c589bf feat(cli): Add dig compatible error exit code 9
This patch implements the error exit code for "No reply from server"
that dig uses to indicate that it was unable to resolve an address due
to the inability to reach any resolver.

References:
https://linux.die.net/man/1/dig
2022-10-19 08:00:48 +05:30
Karan Sharma
0da9178683
Update README.md
Ref https://github.com/mr-karan/doggo/issues/51#issuecomment-1226928372
2022-08-25 15:06:11 +05:30
Karan Sharma
5e611d9706 chore: upgrade go.mod 2022-08-08 12:18:49 +05:30
Zack Gilman
711cb96d9d help.go - Clean up Grammar + Technical Terms
I think "resolver for" should be changed to "query to" if I understand correctly.

Some other minor adjustments that make the help file terminology a bit more uniform.
2022-07-27 12:34:01 +05:30
Zack Gilman
50739e40b3 Add DNS over QUIC (DoQ) to readme 2022-07-27 09:17:56 +05:30
Gaeulbyul
2cf9e7bf2c fix: Correctly print colored text on Windows
This commit will fix #40.

Replacing os.Stdout with color.Output will fix the problem on Windows's console.

Internally, `color.Output` is same as `colorable.NewColorableStdout()`, according to acd5f3bb28/color.go (L25-L27)

see also: https://godocs.io/github.com/mattn/go-colorable#NewColorableStdout
2022-07-13 16:52:59 +05:30
Rui Chen
218eb0233a docs: add homebrew installation note 2022-06-30 19:56:24 +05:30
Rui Chen
c5d0020645 license: add GPL license header
Signed-off-by: Rui Chen <rui@chenrui.dev>
2022-06-30 09:02:31 +05:30
AUTUMN
96e11c01a7 Update doq.go 2022-06-20 08:33:40 +05:30
lyekumchew
2008cd9ed9 chore: impl rfc9250 DoQ client 2022-06-20 08:33:40 +05:30
Karan Sharma
ea7cb3c6cd fix: fallback to tcp if response is truncated
Based on a report `doggo txt google.com  @udp://1.1.1.1` failed.
This record had 704 bytes as the message length however the response
gets truncated if it exceeds 512 bytes with UDP.

`dig` transparently fallbacks to `tcp`, so this commit adds the same
mechanism.
2022-06-02 14:59:27 +05:30
Karan Sharma
53f7b70af4 feat: add tls config for dot lookups
Ref https://github.com/mr-karan/doggo/issues/29
2022-05-18 09:56:07 +05:30
Karan Sharma
0ce04d0c13 fix: rtt time should include tcp.Dial
Ref https://github.com/mr-karan/doggo/issues/39
2022-05-17 23:34:30 +05:30
Karan Sharma
8d705245a1 chore: update docs 2022-05-17 10:50:26 +05:30
Karan Sharma
eec8374e6f feat: Add short output flag
Ref https://github.com/mr-karan/doggo/issues/35
2022-05-17 10:35:18 +05:30
Karan Sharma
7619cbdeb0 feat: add strategy flag
Ref https://github.com/mr-karan/doggo/issues/35
2022-05-17 10:21:14 +05:30
Karan Sharma
79c5fc7283 ci: fix release 2022-03-24 12:43:33 +05:30
Karan Sharma
a855ec4d45 chore: fix docker image tags 2022-03-24 12:30:20 +05:30
Karan Sharma
f753e708c5 chore: fix docker tag 2022-03-24 12:18:34 +05:30
Karan Sharma
7ce6ea7c2c chore: upgrade for go 1.18 2022-03-24 11:28:03 +05:30
YYYMagic
da13887145 docs: use go install 2022-03-07 19:40:03 +05:30
Karan Sharma
9ae8b0a3f2 chore: fix CI 2021-12-20 22:16:40 +05:30
Karan Sharma
b78ee85b04 feat: update docs 2021-12-20 21:45:16 +05:30
lyekumchew
a5fe3ae922 feat: add DNS over QUIC support 2021-12-20 21:43:27 +05:30
Ian Bashford
3d7b4a9821 debug logs DOH response headers 2021-08-11 14:08:50 +05:30
Frank Denis
ddbf40de9a Update the dnscrypt module to version 2 2021-08-03 10:04:04 +05:30
Karan Sharma
6b42a5ecf0 chore: Restructure package directories 2021-06-25 19:02:00 +05:30
Karan Sharma
68fd19d487 fix: Rename CLI binary
Previously binary was named as doggo-cli.bin, which made it difficult
for users building from source as they had to rename it.
2021-06-25 18:00:57 +05:30
Karan Sharma
9e3656fae9 feat: Add support for reverse DNS lookups
Closes https://github.com/mr-karan/doggo/issues/25
2021-06-25 17:25:04 +05:30
Karan Sharma
e5acf1214c fix: prevent app from quitting if one resolver failed 2021-05-18 19:05:47 +05:30
Karan Sharma
f1a1e3aae6 refactor: use switch instead of if 2021-04-25 16:13:39 +05:30
Karan Sharma
d7e7362b57 chore: delete unused files (api) 2021-04-25 16:13:39 +05:30
Frank Denis
310eb2d126 README.md: add DNSCrypt to the list of protocols 2021-04-24 21:57:57 +05:30
Frank Denis
8dc23ce8f5 DoH: fallback to GET if a 405 HTTP status code is returned
Some servers block POST queries. Retry with GET if we receive a
405 HTTP status code.
2021-04-24 21:47:36 +05:30
Frank Denis
9da51ad997 Full stop 2021-04-24 21:47:00 +05:30
Frank Denis
b7e0b497cf Print the server IP address instead of a full DNS stamp
Also allow the sdns scheme in api/index.html
2021-04-24 21:47:00 +05:30
Frank Denis
6d2eae4f58 Add support for DNS stamps and for DNSCrypt servers
This allows connections to DoH servers using their stamp, and adds
support for DNSCrypt servers by the way.
2021-04-24 21:47:00 +05:30
Karan Sharma
48fd5bb792 chore: update docs 2021-04-21 11:42:56 +05:30
Karan Sharma
7b858c5a93 feat: Add shell completions for zsh,fish 2021-04-21 11:40:21 +05:30
Karan Sharma
45dd2e2af2 chore: add URL to README 2021-03-11 12:16:21 +05:30
Karan Sharma
6d6e69b8e4 fix: center elements in page 2021-03-11 12:06:17 +05:30
Karan Sharma
50b8093ee1 fix: custom line-height for headers 2021-03-11 11:29:48 +05:30
Karan Sharma
d09eb901ec fix: line-height for responsive screens 2021-03-11 00:49:57 +05:30
Karan Sharma
3dbfb0a866 chore: fix goreleaser hooks 2021-03-11 00:34:40 +05:30
Karan Sharma
3da7852368 fix: Add spacing on label and form fields 2021-03-11 00:30:24 +05:30
Kailash Nadh
b8ba782cf3 Refactor web frontend and remove unnecessary dependencies.
- Eliminate frontend JS build step completely:
  (remove dep: NodeJS, npx, tailwind, postcss, autoprefixer)

- Declutter and cleanup index.html (8.49 KB to 3.4 KB) = ~60% savings.

- Replace tailwind with custom CSS (10.64 KB to 1.96 KB) = ~81% savings.

- Remove Google font (~100 KB) as there is very little text on the page.

- Refactor and cleanup main.js and remove tailwind styling logic.
  (2.82 KB to 1.12 KB) = ~60% savings.

- Net static asset reduction = 21.95 KB to 6.48 KB = ~70% savings
  apart from the 100+ KB elimination of Google fonts.
2021-03-11 00:29:22 +05:30
Karan Sharma
0dc61ac8ec feat: remove redundant map for nameserver 2021-03-10 16:41:55 +05:30
Karan Sharma
27fa414ca9 chore: fix styles 2021-03-10 16:23:25 +05:30
Karan Sharma
9b7c92698d chore: bg color fix 2021-03-10 14:23:02 +05:30
Karan Sharma
cda2d04974 feat: jazz up form ui 2021-03-10 13:59:27 +05:30
Karan Sharma
52f076d91b feat: Add autofocus to input 2021-03-09 10:48:31 +05:30
Karan Sharma
edb8bb661a fix: bg css for inputs 2021-03-04 21:08:30 +05:30
Karan Sharma
49d5e93316 fix: goreleaser build 2021-03-04 20:41:37 +05:30
Karan Sharma
f83a1d14aa feat: purge unused css in tailwind 2021-03-04 20:35:44 +05:30
Karan Sharma
d985ecd1b4 feat: Remove VueJS and rewrite in vanilla JS 2021-03-04 20:35:44 +05:30
Karan Sharma
022c1267b7 add version 2021-03-03 10:23:26 +05:30
Karan Sharma
06bee3f09c feat: Add DOH option 2021-03-03 10:15:41 +05:30
Karan Sharma
b17d162c24 fix: vue loading issues 2021-03-02 20:13:43 +05:30
Karan Sharma
7ecd7c78d0 chore: load vue on DOMContentLoaded 2021-03-02 19:55:59 +05:30
Karan Sharma
12c5b0b278 fix: Load VueJS before custom js 2021-03-02 19:39:35 +05:30
Karan Sharma
e8a7fc720e chore: remove unused font 2021-03-02 19:31:49 +05:30
Karan Sharma
d9e80b1d17 fix: minor styling changes 2021-03-02 19:14:00 +05:30
33 changed files with 1581 additions and 527 deletions

View file

@ -5,6 +5,9 @@ on:
tags:
- "*"
env:
REGISTRY: ghcr.io
jobs:
goreleaser:
runs-on: ubuntu-latest
@ -16,17 +19,14 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
go-version: 1.19
- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ghcr.io
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ secrets.GH_GORELEASER_TOKEN }}
- name: Install Snapcraft and Log In
uses: samuelmeuli/action-snapcraft@v1
with:
snapcraft_token: ${{ secrets.SNAPCRAFT_TOKEN }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
with:
@ -34,4 +34,4 @@ jobs:
args: release --rm-dist
env:
DOCKER_CLI_EXPERIMENTAL: enabled
GITHUB_TOKEN: ${{ secrets.GH_GORELEASER_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.gitignore vendored
View file

@ -20,3 +20,4 @@ vendor/
config.yml
.DS_Store
bin/*
node_modules

View file

@ -17,7 +17,7 @@ builds:
- 7
ldflags:
- -s -w -X "main.buildVersion={{ .Tag }} ({{ .ShortCommit }} {{ .Date }})"
dir: ./cmd/doggo/cli/
dir: ./cmd/doggo/
- binary: doggo-api.bin
id: api
@ -33,64 +33,62 @@ builds:
- 7
ldflags:
- -s -w -X "main.buildVersion={{ .Tag }} ({{ .ShortCommit }} {{ .Date }})"
dir: ./cmd/doggo/api/
dir: ./cmd/api/
archives:
- format: tar.gz
files:
- README.md
- LICENSE
snapcrafts:
- name_template: "{{ .ProjectName }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
summary: Command-line DNS client.
description: |
doggo is a command-line DNS client written in Go. It supports protocols like DoH, DoT and output formats like JSON.
grade: stable
confinement: strict
publish: true
- completions/
dockers:
- image_templates:
- "ghcr.io/mr-karan/doggo-cli:{{ .Tag }}"
- "ghcr.io/mr-karan/doggo-cli:latest"
binaries:
- doggo
- "ghcr.io/mr-karan/doggo:{{ .Tag }}"
- "ghcr.io/mr-karan/doggo:latest"
id: doggo
# IDs to filter the binaries/packages.
ids:
- cli
dockerfile: Dockerfile-cli
build_flag_templates:
- "--build-arg"
- "ARCH=amd64"
- image_templates:
- "ghcr.io/mr-karan/doggo-cli:{{ .Tag }}-arm64v8"
- "ghcr.io/mr-karan/doggo-cli:latest-arm64v8"
binaries:
- doggo
- "ghcr.io/mr-karan/doggo:{{ .Tag }}-arm64v8"
- "ghcr.io/mr-karan/doggo:latest-arm64v8"
id: doggo-arm
# IDs to filter the binaries/packages.
ids:
- cli
goarch: arm64
dockerfile: Dockerfile-cli
build_flag_templates:
- "--build-arg"
- "ARCH=arm64v8"
- image_templates:
- "ghcr.io/mr-karan/doggo-api:{{ .Tag }}"
- "ghcr.io/mr-karan/doggo-api:latest"
binaries:
- doggo-api.bin
dockerfile: Dockerfile-api
build_flag_templates:
- "--build-arg"
- "ARCH=amd64"
extra_files:
- config-api-sample.toml
- image_templates:
- "ghcr.io/mr-karan/doggo-api:{{ .Tag }}-arm64v8"
- "ghcr.io/mr-karan/doggo-api:latest-arm64v8"
binaries:
- doggo-api.bin
goarch: arm64
dockerfile: Dockerfile-api
build_flag_templates:
- "--build-arg"
- "ARCH=arm64v8"
extra_files:
- config-api-sample.toml
# - image_templates:
# - "ghcr.io/mr-karan/doggo-api:{{ .Tag }}"
# - "ghcr.io/mr-karan/doggo-api:latest"
# id: doggo-api
# ids:
# - api
# dockerfile: Dockerfile-api
# build_flag_templates:
# - "--build-arg"
# - "ARCH=amd64"
# extra_files:
# - config-api-sample.toml
# - image_templates:
# - "ghcr.io/mr-karan/doggo-api:{{ .Tag }}-arm64v8"
# - "ghcr.io/mr-karan/doggo-api:latest-arm64v8"
# id: doggo-api-arm
# ids:
# - api
# goarch: arm64
# dockerfile: Dockerfile-api
# build_flag_templates:
# - "--build-arg"
# - "ARCH=arm64v8"
# extra_files:
# - config-api-sample.toml

View file

@ -1,4 +1,4 @@
CLI_BIN := ./bin/doggo-cli.bin
CLI_BIN := ./bin/doggo.bin
API_BIN := ./bin/doggo-api.bin
HASH := $(shell git rev-parse --short HEAD)
@ -7,12 +7,11 @@ VERSION := ${HASH}
.PHONY: build-cli
build-cli:
go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/cli/
go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/
.PHONY: build-api
build-api:
go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/api/
go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/api/
.PHONY: build
build: build-api build-cli

View file

@ -4,13 +4,15 @@
<h2 align="center">doggo</h2>
<p align="center">
🐶 <i>Command-line DNS client for humans</i>
<br/>
<a href="https://doggo.mrkaran.dev">doggo.mrkaran.dev</a>
</p>
<img src="www/static/doggo.png" alt="doggo CLI usage">
</p>
---
**doggo** is a modern command-line DNS client (like _dig_) written in Golang. It outputs information in a neat concise manner and supports protocols like DoH, DoT as well.
**doggo** is a modern command-line DNS client (like _dig_) written in Golang. It outputs information in a neat concise manner and supports protocols like DoH, DoT, DoQ, and DNSCrypt as well.
It's totally inspired from [dog](https://github.com/ogham/dog/) which is written in Rust. I wanted to add some features to it but since I don't know Rust, I found it as a nice opportunity
to experiment with writing a DNS Client from scratch in `Go` myself. Hence the name `dog` +`go` => **doggo**.
@ -22,23 +24,28 @@ to experiment with writing a DNS Client from scratch in `Go` myself. Hence the n
- Has support for multiple transport protocols:
- DNS over **HTTPS** (DoH)
- DNS over **TLS** (DoT)
- DNS over **QUIC** (DoQ)
- DNS over **TCP**
- DNS over **UDP**
- DNS over **DNSCrypt**
- Supports **ndots** and **search** configurations from `resolv.conf` or command-line arguments.
- Supports multiple resolvers at once.
- Supports IPv4 **and** IPv6 _both_.
- Available as a web tool as well: [https://doggo.mrkaran.dev](https://doggo.mrkaran.dev).
- Shell completions for `zsh` and `fish`.
- Reverse DNS Lookups.
## Installation
### Binary
You can grab the latest binaries for Linux, MacOS and Windows from the [Releases](https://github.com/mr-karan/doggo/releases) section.
You can grab the latest binaries for Linux, MacOS and Windows from the [Releases](https://git.zio.sh/astra/doggo/releases) section.
For eg, to pull the latest Linux binary:
For eg, to pull the latest `linux-amd64` binary:
```shell
$ cd "$(mktemp -d)"
$ curl -sL "https://github.com/mr-karan/doggo/releases/download/v0.2.0/doggo_0.2.0_linux_amd64.tar.gz" | tar xz
$ curl -sL "https://git.zio.sh/astra/doggo/releases/download/v0.3.7/doggo_0.3.7_linux_amd64.tar.gz" | tar xz
$ mv doggo /usr/local/bin
# doggo should be available now in your $PATH
$ doggo
@ -58,24 +65,36 @@ You can supply all arguments to the CLI directly to `docker run` command. Eg:
`docker run ghcr.io/mr-karan/doggo:latest mrkaran.dev @1.1.1.1 MX`
### Using snap
### Package Managers
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/doggo)
#### Homebrew
```sh
$ sudo snap install doggo
Install via [Homebrew](https://brew.sh/)
```bash
$ brew install doggo
```
**NOTE**: Since the [confinement](https://snapcraft.io/docs/snap-confinement) mode is strict as of now, it cannot access your host's `/etc/resolv.conf`.
I'll be making a request in the Snap forums soon so that it can be manually reviewed and allowed to use `--classic`. Until then, please specify a nameserver manually
if using `snap`.
#### Arch
```bash
yay -S doggo-bin
```
#### Scoop
Install via [Scoop](https://scoop.sh/)
```bash
scoop install doggo
```
### From Source
You need to have `go` installed in your system.
```bash
$ go get github.com/mr-karan/doggo/cmd/doggo
$ go install git.zio.sh/astra/doggo/cmd/doggo@latest
```
The binary will be available at `$GOPATH/bin/doggo`.
@ -190,6 +209,10 @@ URL scheme of the server is used to identify which resolver to use for lookups.
@tcp:// eg: @1.1.1.1 initiates a TCP resolver for 1.1.1.1:53.
@https:// eg: @https://cloudflare-dns.com/dns-query initiates a DOH resolver for Cloudflare DoH server.
@tls:// eg: @1.1.1.1 initiates a DoT resolver for 1.1.1.1:853.
@sdns:// eg: @sdns://AgcAAAAAAAAABzEuMC4wLjEAEmRucy5jbG91ZGZsYXJlLmNvbQovZG5zLXF1ZXJ5
initiates a DNSCrypt or DoH resolver using its DNS stamp.
@quic:// eg: @quic://dns.adguard.com
initiates a DNS over QUIC resolver for Adguard DNS Resolver.
```
### Query Options
@ -204,11 +227,14 @@ URL scheme of the server is used to identify which resolver to use for lookups.
### Resolver Options
```
--strategy=STRATEGY Specify strategy to query nameserver listed in etc/resolv.conf. Defaults to `all` (`random`, `first`, `all`).
--ndots=INT Specify ndots parameter. Takes value from /etc/resolv.conf if using the system nameserver or 1 otherwise.
--search Use the search list defined in resolv.conf. Defaults to true. Set --search=false to disable search list.
--timeout Specify timeout (in seconds) for the resolver to return a response.
-4 --ipv4 Use IPv4 only.
-6 --ipv6 Use IPv6 only.
--tls-hostname=HOSTNAME Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP.
--skip-hostname-verification Skip TLS Hostname Verification in case of DOT Lookups.
```
@ -219,6 +245,7 @@ URL scheme of the server is used to identify which resolver to use for lookups.
--color Defaults to true. Set --color=false to disable colored output.
--debug Enable debug logging.
--time Shows how long the response took from the server.
--short Short output format. Shows only the response section.
```
---
@ -231,4 +258,4 @@ For now I am focussing more on [planned features](TODO.md) for a **stable** v1.0
## License
[LICENSE](LICENSE)
[LICENSE](./LICENSE)

12
TODO.md
View file

@ -54,14 +54,16 @@
# Future Release
- [ ] Support obscure protocol tweaks in `dig`
- [ ] Read from file with `-f`
- [x] Support more DNS Record Types
- [ ] Shell completions
- [ ] bash
- [ ] zsh
- [ ] fish
- [x] Shell completions
- [x] zsh
- [x] fish
- [ ] Add tests for Resolvers.
- [ ] Add tests for CLI Output.
- [ ] Homebrew - Goreleaser
- [ ] Add support for `dig +trace` like functionality.
- [ ] Add `dig +short` short output
- [x] Add `--strategy` for picking nameservers.
- [ ] Explore `dig.rc` kinda file
- [x] Separate Authority/Answer in JSON output.
- [x] Error on NXDomain (Related upstream [bug](https://github.com/miekg/dns/issues/1198))

View file

@ -6,8 +6,8 @@ import (
"net/http"
"time"
"github.com/mr-karan/doggo/internal/app"
"github.com/mr-karan/doggo/pkg/utils"
"git.zio.sh/astra/doggo/internal/app"
"git.zio.sh/astra/doggo/pkg/utils"
"github.com/sirupsen/logrus"
"github.com/go-chi/chi"

48
cmd/api/assets/dark.css Normal file
View file

@ -0,0 +1,48 @@
:root {
--primary: #58a6ff;
--background: #0d1117;
}
body {
background-color: var(--background);
color: #c9d1d9;
}
.box {
border: 1px solid #30363d;
box-shadow: unset;
}
.help a {
text-decoration: none;
}
a:hover {
color: var(--primary);
text-decoration: underline;
}
input, select, button {
background-color: #010409;
border: 1px solid #30363d;
color: #ffffff;
}
button {
color: #c9d1d9;
background-color: #21262d;
box-shadow: 0 0 transparent, 0 0 transparent;
}
button:hover,
button:focus {
background-color: #30363d;
border-color: #8b949e;
transition-duration: .1s;
}
table th {
background: #161b22;
border-bottom: unset;
color: #c9d1d9;
}

90
cmd/api/assets/main.js Normal file
View file

@ -0,0 +1,90 @@
const $ = document.querySelector.bind(document);
const $new = document.createElement.bind(document);
const $show = (el) => {
el.classList.remove('hidden');
};
const $hide = (el) => {
el.classList.add('hidden');
};
const apiURL = '/api/lookup/';
(function () {
const fields = ['name', 'address', 'type', 'ttl', 'rtt'];
// createRow creates a table row with the given cell values.
function createRow(item) {
const tr = $new('tr');
fields.forEach((f) => {
const td = $new('td');
td.innerText = item[f];
td.classList.add(f);
tr.appendChild(td);
});
return tr;
}
const handleSubmit = async () => {
const tbody = $('#table tbody'),
tbl = $('#table');
tbody.innerHTML = '';
$hide(tbl);
const q = $('input[name=q]').value.trim(),
typ = $('select[name=type]').value,
addr = $('input[name=address]').value.trim();
// Post to the API.
const req = await fetch(apiURL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: [q,], type: [typ,], nameservers: [addr,] })
});
const res = await req.json();
if (res.status != 'success') {
const error = (res && res.message) || response.statusText;
throw(error);
return;
}
if (res.data[0].answers == null) {
throw('No records found.');
return;
}
res.data[0].answers.forEach((item) => {
tbody.appendChild(createRow(item));
});
$show(tbl);
};
// Capture the form submit.
$('#form').onsubmit = async (e) => {
e.preventDefault();
const msg = $('#message');
$hide(msg);
try {
await handleSubmit();
} catch(e) {
msg.innerText = e.toString();
$show(msg);
throw e;
}
};
// Change the address on ns change.
const ns = $("#ns"), addr = $("#address");
addr.value = ns.value;
ns.onchange = (e) => {
addr.value = e.target.value;
if(addr.value === "") {
addr.focus();
}
};
})();

201
cmd/api/assets/style.css Normal file
View file

@ -0,0 +1,201 @@
:root {
--primary: #4338ca;
--secondary: #333;
}
* {
box-sizing: border-box;
}
:focus {
outline: 0;
}
body {
font-family: "Segoe UI", "Helvetica Neue", Inter, sans-serif;
font-size: 16px;
line-height: 24px;
color: #111;
margin: 0 auto;
}
h1, h2, h3, h4 {
line-height: 1.3em;
}
a {
color: var(--primary);
}
a:hover {
color: #111;
text-decoration: none;
}
input, select, button {
border-radius: 5px;
border: 1px solid #ddd;
font-size: 1.3rem;
padding: 10px 15px;
width: 100%;
}
input:focus, select:focus {
border-color: var(--primary);
}
button {
border-color: var(--primary);
background: var(--primary);
color: #fff;
cursor: pointer;
width: auto;
padding: 10px 30px;
}
button:focus,
button:hover {
border-color: var(--secondary);
background: var(--secondary);
}
label {
display: block;
padding-bottom: 0.5rem;
}
.box {
box-shadow: 1px 1px 4px #eee;
border: 1px solid #eee;
padding: 30px;
border-radius: 3px;
}
.hidden {
display: none !important;
}
.main {
margin: 60px auto 30px auto;
max-width: 900px;
}
header {
text-align: center;
font-size: 1.5em;
margin-bottom: 60px;
}
.logo span {
color: var(--primary);
font-weight: 900;
}
form {
margin-bottom: 45px;
}
.row {
display: flex;
margin-bottom: 15px;
}
.row .field {
flex: 50%;
}
.row .field:last-child {
margin-left: 30px;
}
.submit {
text-align: right;
}
.help {
color: #666;
font-size: 0.875em;
}
#message {
color: #ff3300;
}
table.box {
width: 100%;
max-width: 100%;
padding: 0;
}
table th {
background: #f9fafb;
color: #666;
font-size: 0.875em;
border-bottom: 1px solid #ddd;
}
table th, tbody td {
padding: 10px 15px;
text-align: left;
}
td.name {
font-weight: bold;
}
th.type, td.type {
text-align: center;
}
td.type {
background: #d1fae5;
color: #065f46;
font-weight: bold;
}
footer {
margin: 60px 0 0 0;
text-align: center;
}
footer a {
text-decoration: none;
}
@media (max-width: 650px) {
.main {
margin: 60px 30px 30px 30px;
}
.box {
box-shadow: none;
border: 0;
padding: 0;
}
.row {
display: block;
}
.field {
margin: 0 0 20px 0;
}
.row .field:last-child {
margin: 0;
}
.submit button {
width: 100%;
}
table {
table-layout: fixed;
}
table th {
width: 100%;
}
table tr {
border-bottom: 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-bottom: 30px;
}
table td {
border: 1px solid #eee;
margin: 0 -1px -1px 0;
position: relative;
width: 100%;
word-wrap:break-word;
}
table th.type, table td.type {
text-align: left;
}
table td span {
display: block;
}
}

View file

@ -8,9 +8,9 @@ import (
"net/http"
"time"
"github.com/mr-karan/doggo/internal/app"
"github.com/mr-karan/doggo/pkg/models"
"github.com/mr-karan/doggo/pkg/resolvers"
"git.zio.sh/astra/doggo/internal/app"
"git.zio.sh/astra/doggo/pkg/models"
"git.zio.sh/astra/doggo/pkg/resolvers"
)
type httpResp struct {
@ -20,7 +20,11 @@ type httpResp struct {
}
func handleIndexAPI(w http.ResponseWriter, r *http.Request) {
sendResponse(w, http.StatusOK, "Welcome to Doggo API.")
var (
app = r.Context().Value("app").(app.App)
)
sendResponse(w, http.StatusOK, fmt.Sprintf("Welcome to Doggo API. Version: %s", app.Version))
return
}
@ -66,7 +70,7 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
err = app.LoadNameservers()
if err != nil {
app.Logger.WithError(err).Error("error loading nameservers")
sendErrorResponse(w, fmt.Sprintf("Error lookuping up for records."), http.StatusInternalServerError, nil)
sendErrorResponse(w, fmt.Sprintf("Error looking up for records."), http.StatusInternalServerError, nil)
return
}
@ -82,7 +86,7 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
})
if err != nil {
app.Logger.WithError(err).Error("error loading resolver")
sendErrorResponse(w, fmt.Sprintf("Error lookuping up for records."), http.StatusInternalServerError, nil)
sendErrorResponse(w, fmt.Sprintf("Error looking up for records."), http.StatusInternalServerError, nil)
return
}
app.Resolvers = rslvrs
@ -93,7 +97,7 @@ func handleLookup(w http.ResponseWriter, r *http.Request) {
resp, err := rslv.Lookup(q)
if err != nil {
app.Logger.WithError(err).Error("error looking up DNS records")
sendErrorResponse(w, fmt.Sprintf("Error lookuping up for records."), http.StatusInternalServerError, nil)
sendErrorResponse(w, fmt.Sprintf("Error looking up for records."), http.StatusInternalServerError, nil)
return
}
responses = append(responses, resp)

101
cmd/api/index.html Normal file
View file

@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head>
<title>Doggo DNS</title>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link href="assets/style.css" rel="stylesheet">
<link href="assets/dark.css" rel="stylesheet">
</head>
<body>
<div class="main">
<header>
<h1 class="logo"><span>Doggo</span> DNS</h1>
</header>
<form method="post" id="form" class="box">
<div class="row">
<div class="field">
<label for="domain">Domain name</label>
<input id="domain" name="q" placeholder="domain.tld" required autofocus />
</div>
<div class="field">
<label for="type">Query type</label>
<select id="type" name="type">
<option default>A</option>
<option>AAAA</option>
<option>CAA</option>
<option>CNAME</option>
<option>MX</option>
<option>NAPTR</option>
<option>NS</option>
<option>PTR</option>
<option>SOA</option>
<option>SRV</option>
<option>TXT</option>
</select>
</div>
</div>
<div class="row">
<div class="field">
<label for="ns">Nameserver</label>
<select id="ns" name="ns">
<option default value="tcp://1.1.1.1:53">Cloudflare</option>
<option value="https://cloudflare-dns.com/dns-query">Cloudflare (DOH)</option>
<option value="tcp://8.8.8.8:53">Google</option>
<option value="tcp://9.9.9.9:53">Quad9</option>
<option value="">Custom</option>
</select>
</div>
<div class="field">
<label for="address">Nameserver address</label>
<input id="address" name="address" type="text" placeholder="tcp://your-ip"
required pattern="(tcp|udp|tls|https|sdns):\/\/(.*)" />
<p class="help">
To use different protocols like DOH, DOT etc. refer to the instructions
<a href="https://git.zio.sh/astra/doggo#transport-options">here</a>.
</p>
</div>
</div>
<div class="row">
<div class="field"><p id="message"></p></div>
<div class="field submit">
<button type="submit">Submit</button>
</div>
</div>
</form>
<!--Responses-->
<table class="box hidden" id="table">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th class="type">Type</th>
<th>TTL</th>
<th>RTT</th>
</tr>
</thead>
<tbody></tbody>
</table>
<footer >
<div>
<p>Built with
<span>&#9829;</span> by
<a href="https://mrkaran.dev"><strong>mrkaran</strong></a>
</p>
<p><a href="https://git.zio.sh/astra/doggo">Source Code</a></p>
</div>
</footer>
<script src="assets/main.js"> </script>
<noscript>
<div class="noscript">
<h2>This service requires Javascript</h2>
<p>Please enable JavaScript so that the form data can be sent to the API backend.</p>
</div>
</noscript>
</div>
</body>
</html>

View file

@ -1,92 +0,0 @@
var app = new Vue({
el: '#app',
data: {
apiURL: "/api/lookup/",
results: [],
noRecordsFound: false,
emptyNameError: false,
apiErrorMessage: "",
queryName: "",
queryType: "A",
nameserverName: "google",
customNSAddr: "",
nsAddrMap: {
"google": "8.8.8.8",
"cloudflare": "1.1.1.1",
"quad9": "9.9.9.9",
}
},
created: function () {
},
computed: {
getNSAddrValue() {
return this.nsAddrMap[this.nameserverName]
},
isCustomNS() {
if (this.nameserverName == "custom") {
return true
}
return false
}
},
methods: {
prepareNS() {
switch (this.nameserverName) {
case "google":
return "tcp://8.8.8.8:53"
case "cloudflare":
return "tcp://1.1.1.1:53"
case "quad9":
return "tcp://9.9.9.9:53"
case "custom":
return this.customNSAddr
default:
return ""
}
},
lookupRecords() {
// reset variables.
this.results = []
this.noRecordsFound = false
this.emptyNameError = false
this.apiErrorMessage = ""
if (this.queryName == "") {
this.emptyNameError = true
return
}
// GET request using fetch with error handling
fetch(this.apiURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: [this.queryName,],
type: [this.queryType,],
nameservers: [this.prepareNS(),],
}),
}).then(async response => {
const res = await response.json();
// check for error response
if (!response.ok) {
// get error message from body or default to response statusText
const error = (res && res.message) || response.statusText;
return Promise.reject(error);
}
if (res.data[0].answers == null) {
this.noRecordsFound = true
} else {
// Set the answers in the results list.
this.results = res.data[0].answers
}
}).catch(error => {
this.apiErrorMessage = error
});
}
}
})

View file

@ -1,195 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Doggo DNS</title>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&family=Poppins:wght@400;600;700&display=swap"
rel="stylesheet">
</head>
<style>
body {
font-family: 'Poppins', sans-serif;
}
</style>
<noscript>
<div class="noscript">
<h2>This service requires Javascript</h2>
<p>Please enable JavaScript so that the form data can be sent to the API backend.</p>
</div>
</noscript>
<body class="m-4 max-w-screen-lg m-auto">
<header class="mt-10">
<h1 class="text-5xl font-black text-center"><span class="text-indigo-700">Doggo</span> DNS</h1>
</header>
<main id="app">
<form @submit.prevent="lookupRecords">
<div class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4 flex flex-col my-2">
<div class="-mx-3 md:flex mb-6">
<div class="md:w-1/2 px-3 mb-6 md:mb-0">
<label class="block tracking-wide text-grey-darker text-xs font-bold mb-2">
Domain Name
</label>
<input v-model="queryName"
class="appearance-none block w-full bg-grey-lighter text-grey-darker border border-red rounded py-3 px-4 mb-3"
type="text" placeholder="domain.tld">
<p v-if="emptyNameError" class="text-red-500 text-xs">Please enter a domain name to
query.
</p>
</div>
<div class="md:w-1/2 px-3">
<label class="block tracking-wide text-grey-darker text-xs font-bold mb-2" for="grid-state">
Query Type
</label>
<select
class="block appearance-none w-full bg-grey-lighter border border-grey-lighter text-grey-darker py-3 px-4 pr-8 rounded"
v-model="queryType">
<option>A</option>
<option>AAAA</option>
<option>CNAME</option>
<option>MX</option>
<option>TXT</option>
<option>CAA</option>
<option>NAPTR</option>
<option>NS</option>
<option>PTR</option>
<option>SOA</option>
<option>SRV</option>
</select>
</div>
</div>
<div class="-mx-3 md:flex">
<div class="md:w-1/2 px-3 mb-6 md:mb-0">
<label class="block tracking-wide text-grey-darker text-xs font-bold mb-2" for="grid-state">
Nameserver
</label>
<select v-model="nameserverName"
class="block appearance-none w-full bg-grey-lighter border border-grey-lighter text-grey-darker py-3 px-4 pr-8 rounded"
id="grid-state">
<option value="google">Google</option>
<option value="cloudflare">Cloudflare</option>
<option value="quad9">Quad9</option>
<option value="custom">Custom</option>
</select>
</div>
<div class="md:w-1/2 px-3">
<label class="block tracking-wide text-grey-darker text-xs font-bold mb-2" for="grid-zip">
Address
</label>
<div v-if="isCustomNS">
<input v-model="customNSAddr" class="appearance-none block w-full bg-grey-lighter text-grey-darker border
border-grey-lighter rounded py-3 px-4" id="grid-zip" type="text"
placeholder="Enter Nameserver address">
<p class="mt-2 text-grey-darker text-xs">To use different protocols like DOH, DOT etc. refer
to the
instructions <a class="font-semibold"
href="https://github.com/mr-karan/doggo#transport-options">here</a>.</p>
</div>
<div v-else>
<input readonly
class="appearance-none block w-full bg-grey-lighter text-grey-darker border border-grey-lighter rounded py-3 px-4"
id="grid-zip" type="text" :placeholder="getNSAddrValue">
</div>
</div>
</div>
<div class="mt-8 text-right">
<button type="submit" class="py-2 px-10 text-white rounded-xl bg-indigo-800">Submit</button>
</div>
</div>
</form>
<!--Responses-->
<div v-if="Object.keys(results).length > 0" class="mt-12 flex flex-col">
<div class="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8 sm:block hidden">
<div class="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div class="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th scope="col"
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
Name
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
Address
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
Type
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
TTL
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
RTT
</th>
<th scope="col"
class="px-6 py-3 text-left text-xs font-bold text-gray-500 uppercase tracking-wider">
Nameserver
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr v-for="answer in results">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900 font-medium">
{{answer.name}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{{answer.address}}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
{{answer.type}}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{answer.ttl}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{answer.rtt}}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
{{answer.nameserver}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!--On Mobile-->
<ul v-for="answer in results" class="m-4 sm:hidden block bg-indigo-100">
<li><span class="p-2 text-gray-500 font-semibold">Name:</span> {{answer.name}}</li>
<li><span class="p-2 text-gray-500 font-semibold">Address:</span> {{answer.address}}</li>
<li><span class="p-2 text-gray-500 font-semibold">Type:</span> {{answer.type}}</li>
<li><span class="p-2 text-gray-500 font-semibold">Nameserver:</span> {{answer.nameserver}}</li>
<li><span class="p-2 text-gray-500 font-semibold">TTL:</span> {{answer.ttl}}</li>
<li><span class="p-2 text-gray-500 font-semibold">RTT:</span> {{answer.rtt}}</li>
</ul>
</div>
<!--No Answers-->
<div v-if="noRecordsFound" class="mt-12 text-center">
<p class="text-xl text-gray-900">Oops! Found no records for this query.</p>
</div>
<!--Show Error-->
<div v-if="apiErrorMessage" class="mt-12 text-center">
<p class="text-xl text-red-500">{{apiErrorMessage}}</p>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
<script src="assets/main.js"> </script>
</body>

View file

@ -1,14 +1,15 @@
package main
import (
"fmt"
"os"
"time"
"git.zio.sh/astra/doggo/internal/app"
"git.zio.sh/astra/doggo/pkg/resolvers"
"git.zio.sh/astra/doggo/pkg/utils"
"github.com/knadh/koanf"
"github.com/knadh/koanf/providers/posflag"
"github.com/mr-karan/doggo/internal/app"
"github.com/mr-karan/doggo/pkg/resolvers"
"github.com/mr-karan/doggo/pkg/utils"
"github.com/sirupsen/logrus"
flag "github.com/spf13/pflag"
)
@ -35,7 +36,8 @@ func main() {
f.StringSliceP("query", "q", []string{}, "Domain name to query")
f.StringSliceP("type", "t", []string{}, "Type of DNS record to be queried (A, AAAA, MX etc)")
f.StringSliceP("class", "c", []string{}, "Network class of the DNS record to be queried (IN, CH, HS etc)")
f.StringSliceP("nameservers", "n", []string{}, "Address of the nameserver to send packets to")
f.StringSliceP("nameserver", "n", []string{}, "Address of the nameserver to send packets to")
f.BoolP("reverse", "x", false, "Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively.")
// Resolver Options
f.Int("timeout", 5, "Sets the timeout for a query to T seconds. The default timeout is 5 seconds.")
@ -43,13 +45,19 @@ func main() {
f.Int("ndots", -1, "Specify the ndots parameter. Default value is taken from resolv.conf and fallbacks to 1 if ndots statement is missing in resolv.conf")
f.BoolP("ipv4", "4", false, "Use IPv4 only")
f.BoolP("ipv6", "6", false, "Use IPv6 only")
f.String("strategy", "all", "Strategy to query nameservers in resolv.conf file (`all`, `random`, `first`)")
f.String("tls-hostname", "", "Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP")
f.Bool("skip-hostname-verification", false, "Skip TLS Hostname Verification")
// Output Options
f.BoolP("json", "J", false, "Set the output format as JSON")
f.Bool("short", false, "Short output format")
f.Bool("time", false, "Display how long it took for the response to arrive")
f.Bool("color", true, "Show colored output")
f.Bool("debug", false, "Enable debug mode")
f.Bool("version", false, "Show version of doggo")
// Parse and Load Flags.
err := f.Parse(os.Args[1:])
if err != nil {
@ -62,6 +70,12 @@ func main() {
app.Logger.Exit(2)
}
// If version flag is set, output version and quit.
if k.Bool("version") {
fmt.Printf("%s - %s\n", buildVersion, buildDate)
app.Logger.Exit(0)
}
// Set log level.
if k.Bool("debug") {
// Set logger level
@ -85,6 +99,15 @@ func main() {
app.QueryFlags.QClasses = append(app.QueryFlags.QClasses, qc...)
app.QueryFlags.QNames = append(app.QueryFlags.QNames, qn...)
// Check if reverse flag is passed. If it is, then set
// query type as PTR and query class as IN.
// Modify query name like 94.2.0.192.in-addr.arpa if it's an IPv4 address.
// Use IP6.ARPA nibble format otherwise.
if app.QueryFlags.ReverseLookup {
app.ReverseLookup()
}
// Load fallbacks.
app.LoadFallbacks()
@ -107,6 +130,9 @@ func main() {
Ndots: app.ResolverOpts.Ndots,
Timeout: app.QueryFlags.Timeout * time.Second,
Logger: app.Logger,
Strategy: app.QueryFlags.Strategy,
InsecureSkipVerify: app.QueryFlags.InsecureSkipVerify,
TLSHostname: app.QueryFlags.TLSHostname,
})
if err != nil {
app.Logger.WithError(err).Error("error loading resolver")
@ -122,17 +148,25 @@ func main() {
}
// Resolve Queries.
var responses []resolvers.Response
var (
responses []resolvers.Response
responseErrors []error
)
for _, q := range app.Questions {
for _, rslv := range app.Resolvers {
resp, err := rslv.Lookup(q)
if err != nil {
app.Logger.WithError(err).Error("error looking up DNS records")
app.Logger.Exit(2)
responseErrors = append(responseErrors, err)
}
responses = append(responses, resp)
}
}
if len(responses) == 0 && len(responseErrors) > 0 {
app.Logger.Exit(9)
}
app.Output(responses)
// Quitting.

View file

@ -20,38 +20,46 @@ var appHelpTextTemplate = `{{ "NAME" | color "" "heading" }}:
{{ "EXAMPLES" | color "" "heading" }}:
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev" | color "cyan" "" }} Query a domain using defaults.
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev CNAME" | color "cyan" "" }} Looks up for a CNAME record.
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev CNAME" | color "cyan" "" }} Query for a CNAME record.
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev MX @9.9.9.9" | color "cyan" "" }} Uses a custom DNS resolver.
{{ .Name | color "green" "bold" }} {{"-q mrkaran.dev -t MX -n 1.1.1.1" | color "yellow" ""}} Using named arguments.
{{ "Free Form Arguments" | color "" "heading" }}:
Supply hostnames, query types, classes without any flag. For eg:
Supply hostnames, query types, and classes without flags. Example:
{{ .Name | color "green" "bold" }} {{"mrkaran.dev A @1.1.1.1" | color "cyan" "" }}
{{ "Transport Options" | color "" "heading" }}:
Based on the URL scheme the correct resolver is chosen.
Fallbacks to UDP resolver if no scheme is present.
Specify the protocol with a URL-type scheme.
UDP is used if no scheme is specified.
{{"@udp://" | color "yellow" ""}} eg: @1.1.1.1 initiates a {{"UDP" | color "cyan" ""}} resolver for 1.1.1.1:53.
{{"@tcp://" | color "yellow" ""}} eg: @tcp://1.1.1.1 initiates a {{"TCP" | color "cyan" ""}} resolver for 1.1.1.1:53.
{{"@https://" | color "yellow" ""}} eg: @https://cloudflare-dns.com/dns-query initiates a {{"DOH" | color "cyan" ""}} resolver for Cloudflare DoH server.
{{"@tls://" | color "yellow" ""}} eg: @tls://1.1.1.1 initiates a {{"DoT" | color "cyan" ""}} resolver for 1.1.1.1:853.
{{"@udp://" | color "yellow" ""}} eg: @1.1.1.1 initiates a {{"UDP" | color "cyan" ""}} query to 1.1.1.1:53.
{{"@tcp://" | color "yellow" ""}} eg: @tcp://1.1.1.1 initiates a {{"TCP" | color "cyan" ""}} query to 1.1.1.1:53.
{{"@https://" | color "yellow" ""}} eg: @https://cloudflare-dns.com/dns-query initiates a {{"DOH" | color "cyan" ""}} query to Cloudflare via DoH.
{{"@tls://" | color "yellow" ""}} eg: @tls://1.1.1.1 initiates a {{"DoT" | color "cyan" ""}} query to 1.1.1.1:853.
{{"@sdns://" | color "yellow" ""}} initiates a {{"DNSCrypt" | color "cyan" ""}} or {{"DoH" | color "cyan" ""}} query using a DNS stamp.
{{"@quic://" | color "yellow" ""}} initiates a {{"DOQ" | color "cyan" ""}} query.
{{ "Query Options" | color "" "heading" }}:
{{"-q, --query=HOSTNAME" | color "yellow" ""}} Hostname to query the DNS records for (eg {{"mrkaran.dev" | color "cyan" ""}}).
{{"-t, --type=TYPE" | color "yellow" ""}} Type of the DNS Record ({{"A, MX, NS" | color "cyan" ""}} etc).
{{"-n, --nameserver=ADDR" | color "yellow" ""}} Address of a specific nameserver to send queries to ({{"9.9.9.9, 8.8.8.8" | color "cyan" ""}} etc).
{{"-c, --class=CLASS" | color "yellow" ""}} Network class of the DNS record ({{"IN, CH, HS" | color "cyan" ""}} etc).
{{"-x, --reverse" | color "yellow" ""}} Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively.
{{ "Resolver Options" | color "" "heading" }}:
{{"--strategy=STRATEGY" | color "yellow" ""}} Specify strategy to query nameserver listed in etc/resolv.conf. ({{"all, random, first" | color "cyan" ""}}).
{{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise.
{{"--search" | color "yellow" ""}} Use the search list defined in resolv.conf. Defaults to true. Set --search=false to disable search list.
{{"--timeout" | color "yellow" ""}} Specify timeout (in seconds) for the resolver to return a response.
{{"-4 --ipv4" | color "yellow" ""}} Use IPv4 only.
{{"-6 --ipv6" | color "yellow" ""}} Use IPv6 only.
{{"--ndots=INT" | color "yellow" ""}} Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise.
{{"--tls-hostname=HOSTNAME" | color "yellow" ""}} Provide a hostname for doing verification of the certificate if the provided DoT nameserver is an IP.
{{"--skip-hostname-verification" | color "yellow" ""}} Skip TLS Hostname Verification in case of DOT Lookups.
{{ "Output Options" | color "" "heading" }}:
{{"-J, --json " | color "yellow" ""}} Format the output as JSON.
{{"--short" | color "yellow" ""}} Short output format. Shows only the response section.
{{"--color " | color "yellow" ""}} Defaults to true. Set --color=false to disable colored output.
{{"--debug " | color "yellow" ""}} Enable debug logging.
{{"--time" | color "yellow" ""}} Shows how long the response took from the server.
@ -92,7 +100,7 @@ func renderCustomHelp() {
// should ideally never happen.
panic(err)
}
err = tmpl.Execute(os.Stdout, helpTmplVars)
err = tmpl.Execute(color.Output, helpTmplVars)
if err != nil {
// should ideally never happen.
panic(err)

28
completions/doggo.fish Normal file
View file

@ -0,0 +1,28 @@
# Meta options
complete -c doggo -l 'version' -d "Show version of doggo"
complete -c doggo -l 'help' -d "Show list of command-line options"
# Single line all options
complete -c doggo -x -a "(__fish_print_hostnames) A AAAA CAA CNAME HINFO MX NS PTR SOA SRV TXT IN CH HS"
# Query options
complete -c doggo -s 'q' -l 'query' -d "Hostname to query the DNS records for" -x -a "(__fish_print_hostnames)"
complete -c doggo -s 't' -l 'type' -d "Type of the DNS Record" -x -a "A AAAA CAA CNAME HINFO MX NS PTR SOA SRV TXT"
complete -c doggo -s 'n' -l 'nameserver' -d "Address of a specific nameserver to send queries to" -x -a "1.1.1.1 8.8.8.8 9.9.9.9 (__fish_print_hostnames)"
complete -c doggo -s 'c' -l 'class' -d "Network class of the DNS record being queried" -x -a "IN CH HS"
# Transport options
complete -c doggo -x -a "@udp:// @tcp:// @https:// @tls:// @sdns://" -d "Select the protocol for resolving queries"
# Resolver options
complete -c doggo -l 'ndots' -d "Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise"
complete -c doggo -l 'search' -d "Use the search list defined in resolv.conf. Defaults to true. Set --search=false to disable search list"
complete -c doggo -l 'timeout' -d "Specify timeout (in seconds) for the resolver to return a response"
complete -c doggo -s '-4' -l 'ipv4' -d "Use IPv4 only"
complete -c doggo -s '-6' -l 'ipv6' -d "Use IPv6 only"
# Output options
complete -c doggo -s 'J' -l 'json' -d "Format the output as JSON"
complete -c doggo -l 'color' -d "Defaults to true. Set --color=false to disable colored output"
complete -c doggo -l 'debug' -d "Enable debug logging"
complete -c doggo -l 'time' -d "Shows how long the response took from the server"

18
completions/doggo.zsh Normal file
View file

@ -0,0 +1,18 @@
#compdef doggo
__doggo() {
_arguments \
"(- 1 *)"{-v,--version}"[Show version of doggo]" \
"(- 1 *)"{-\?,--help}"[Show list of command-line options]" \
{-q,--query}"[Hostname to query the DNS records for]::_hosts" \
{-t,--type}"[Type of the DNS Record]:(record type):(A AAAA CAA CNAME HINFO MX NS PTR SOA SRV TXT)" \
{-n,--nameserver}"[Address of a specific nameserver to send queries to]::_hosts;" \
{-c,--class}"[Network class of the DNS record being queried]:(network class):(IN CH HS)" \
{-J,--json}"[Format the output as JSON]" \
{--color}"[Defaults to true. Set --color=false to disable colored output]:(setting):(true false)" \
{--debug}"[Enable debug logging]:(setting):(true false)" \
--time"[Shows how long the response took from the server"] \
'*:filename:_hosts'
}
__doggo

50
go.mod
View file

@ -1,17 +1,43 @@
module github.com/mr-karan/doggo
module git.zio.sh/astra/doggo
go 1.16
go 1.19
require (
github.com/fatih/color v1.10.0
github.com/go-chi/chi v1.5.3
github.com/go-chi/render v1.0.1
github.com/knadh/koanf v0.14.0
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/miekg/dns v1.1.35
github.com/olekukonko/tablewriter v0.0.4
github.com/sirupsen/logrus v1.7.0
github.com/ameshkov/dnscrypt/v2 v2.2.5
github.com/ameshkov/dnsstamps v1.0.3
github.com/fatih/color v1.13.0
github.com/go-chi/chi v1.5.4
github.com/knadh/koanf v1.4.4
github.com/miekg/dns v1.1.50
github.com/olekukonko/tablewriter v0.0.5
github.com/quic-go/quic-go v0.33.0
github.com/sirupsen/logrus v1.9.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1 // indirect
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d
golang.org/x/sys v0.3.0
)
require (
github.com/AdguardTeam/golibs v0.11.3 // indirect
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.6.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
golang.org/x/crypto v0.4.0 // indirect
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/net v0.4.0 // indirect
golang.org/x/tools v0.4.0 // indirect
)

453
go.sum
View file

@ -1,73 +1,458 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/AdguardTeam/golibs v0.11.3 h1:Oif+REq2WLycQ2Xm3ZPmJdfftptss0HbGWbxdFaC310=
github.com/AdguardTeam/golibs v0.11.3/go.mod h1:87bN2x4VsTritptE3XZg9l8T6gznWsIxHBcQ1DeRIXA=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 h1:52m0LGchQBBVqJRyYYufQuIbVqRawmubW3OFGqK1ekw=
github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV291OopO93Bwf9fQLQeLyt33VJRUg5VJ30us=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/ameshkov/dnscrypt/v2 v2.2.5 h1:Ju1gQeez+6XLtk/b/k3RoJ2t+Ls+BSItLTZjZeedneY=
github.com/ameshkov/dnscrypt/v2 v2.2.5/go.mod h1:Cu5GgMvCR10BeXgACiGDwXyOpfMktsSIidml1XBp6uM=
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
github.com/ameshkov/dnsstamps v1.0.3/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw=
github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ=
github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8=
github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk=
github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
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/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-chi/chi v1.5.3 h1:+DVDS9/D3MTbEu3WrrH3oz9oP6PlSPSNj8LLw3X17yU=
github.com/go-chi/chi v1.5.3/go.mod h1:Q8xfe6s3fjZyMr8ZTv5jL+vxhVaFyCq2s+RvSfzTD0E=
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
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/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
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.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
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.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/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/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/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-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811 h1:wORs2YN3R3ona/CXYuTvLM31QlgoNKHvlCNuArCDDCU=
github.com/google/pprof v0.0.0-20221219190121-3cb0bae90811/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs=
github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/knadh/koanf v0.14.0 h1:h9XeG4wEiEuxdxqv/SbY7TEK+7vzrg/dOaGB+S6+mPo=
github.com/knadh/koanf v0.14.0/go.mod h1:H5mEFsTeWizwFXHKtsITL5ipsLTuAMQoGuQpp+1JL9U=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knadh/koanf v1.4.4 h1:d2jY5nCCeoaiqvEKSBW9rEc93EfNy/XWgWsSB3j7JEA=
github.com/knadh/koanf v1.4.4/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/miekg/dns v1.1.35 h1:oTfOaDH+mZkdcgdIjH6yBajRGtIwcwcaR+rt23ZSrJs=
github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q=
github.com/onsi/ginkgo/v2 v2.6.1/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
github.com/onsi/gomega v1.24.1 h1:KORJXNNTzJXzu4ScJWssJfJMnJ+2QJqhoQSRwNlze9E=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.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/rhnvrm/simples3 v0.5.0/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
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.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/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-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30 h1:m9O6OTJ627iFnN2JIWfdqlZCzneRO6EEBsHXI25P8ws=
golang.org/x/exp v0.0.0-20221230185412-738e83a70c30/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
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/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
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-20181114220301-adae6a3d119a/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
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-20190911185100-cd5d95a43a6e/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/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-20210603081109-ebe580a85c40/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/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/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
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.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
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-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
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.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
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.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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.0-20210107192922-496545a6307b/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=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View file

@ -1,9 +1,9 @@
package app
import (
"git.zio.sh/astra/doggo/pkg/models"
"git.zio.sh/astra/doggo/pkg/resolvers"
"github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/models"
"github.com/mr-karan/doggo/pkg/resolvers"
"github.com/sirupsen/logrus"
)

View file

@ -2,11 +2,14 @@ package app
import (
"fmt"
"math/rand"
"net"
"net/url"
"time"
"github.com/mr-karan/doggo/pkg/config"
"github.com/mr-karan/doggo/pkg/models"
"git.zio.sh/astra/doggo/pkg/config"
"git.zio.sh/astra/doggo/pkg/models"
"github.com/ameshkov/dnsstamps"
)
// LoadNameservers reads all the user given
@ -28,7 +31,7 @@ func (app *App) LoadNameservers() error {
// fallback to system nameserver
// in case no nameserver is specified by user.
if len(app.Nameservers) == 0 {
ns, ndots, search, err := getDefaultServers()
ns, ndots, search, err := getDefaultServers(app.QueryFlags.Strategy)
if err != nil {
return fmt.Errorf("error fetching system default nameserver")
}
@ -58,45 +61,98 @@ func initNameserver(n string) (models.Nameserver, error) {
}
u, err := url.Parse(n)
if err != nil {
ip := net.ParseIP(n)
if ip == nil {
return ns, err
}
if u.Scheme == "https" {
return ns, nil
}
switch u.Scheme {
case "sdns":
stamp, err := dnsstamps.NewServerStampFromString(n)
if err != nil {
return ns, err
}
switch stamp.Proto {
case dnsstamps.StampProtoTypeDoH:
ns.Type = models.DOHResolver
address := url.URL{Scheme: "https", Host: stamp.ProviderName, Path: stamp.Path}
ns.Address = address.String()
case dnsstamps.StampProtoTypeDNSCrypt:
ns.Type = models.DNSCryptResolver
ns.Address = n
default:
return ns, fmt.Errorf("unsupported protocol: %v", stamp.Proto.String())
}
case "https":
ns.Type = models.DOHResolver
ns.Address = u.String()
}
if u.Scheme == "tls" {
case "tls":
ns.Type = models.DOTResolver
if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultTLSPort)
} else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
}
}
if u.Scheme == "tcp" {
case "tcp":
ns.Type = models.TCPResolver
if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultTCPPort)
} else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
}
}
if u.Scheme == "udp" {
case "udp":
ns.Type = models.UDPResolver
if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultUDPPort)
} else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
}
case "quic":
ns.Type = models.DOQResolver
if u.Port() == "" {
ns.Address = net.JoinHostPort(u.Hostname(), models.DefaultDOQPort)
} else {
ns.Address = net.JoinHostPort(u.Hostname(), u.Port())
}
}
return ns, nil
}
func getDefaultServers() ([]models.Nameserver, int, []string, error) {
func getDefaultServers(strategy string) ([]models.Nameserver, int, []string, error) {
// Load nameservers from `/etc/resolv.conf`.
dnsServers, ndots, search, err := config.GetDefaultServers()
if err != nil {
return nil, 0, nil, err
}
servers := make([]models.Nameserver, 0, len(dnsServers))
switch strategy {
case "random":
// Choose a random server from the list.
rand.Seed(time.Now().Unix())
srv := dnsServers[rand.Intn(len(dnsServers))]
ns := models.Nameserver{
Type: models.UDPResolver,
Address: net.JoinHostPort(srv, models.DefaultUDPPort),
}
servers = append(servers, ns)
case "first":
// Choose the first from the list, always.
srv := dnsServers[0]
ns := models.Nameserver{
Type: models.UDPResolver,
Address: net.JoinHostPort(srv, models.DefaultUDPPort),
}
servers = append(servers, ns)
default:
// Default behaviour is to load all nameservers.
for _, s := range dnsServers {
ns := models.Nameserver{
Type: models.UDPResolver,
@ -104,5 +160,7 @@ func getDefaultServers() ([]models.Nameserver, int, []string, error) {
}
servers = append(servers, ns)
}
}
return servers, ndots, search, nil
}

View file

@ -3,11 +3,10 @@ package app
import (
"encoding/json"
"fmt"
"os"
"git.zio.sh/astra/doggo/pkg/resolvers"
"github.com/fatih/color"
"github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/resolvers"
"github.com/olekukonko/tablewriter"
)
@ -21,6 +20,14 @@ func (app *App) outputJSON(rsp []resolvers.Response) {
fmt.Printf("%s", res)
}
func (app *App) outputShort(rsp []resolvers.Response) {
for _, r := range rsp {
for _, a := range r.Answers {
fmt.Printf("%s\n", a.Address)
}
}
}
func (app *App) outputTerminal(rsp []resolvers.Response) {
var (
green = color.New(color.FgGreen, color.Bold).SprintFunc()
@ -37,7 +44,7 @@ func (app *App) outputTerminal(rsp []resolvers.Response) {
}
// Conditional Time column.
table := tablewriter.NewWriter(os.Stdout)
table := tablewriter.NewWriter(color.Output)
header := []string{"Name", "Type", "Class", "TTL", "Address", "Nameserver"}
if app.QueryFlags.DisplayTimeTaken {
header = append(header, "Time Taken")
@ -134,6 +141,8 @@ func (app *App) outputTerminal(rsp []resolvers.Response) {
func (app *App) Output(responses []resolvers.Response) {
if app.QueryFlags.ShowJSON {
app.outputJSON(responses)
} else if app.QueryFlags.ShortOutput {
app.outputShort(responses)
} else {
app.outputTerminal(responses)
}

View file

@ -33,3 +33,23 @@ func (app *App) PrepareQuestions() {
}
}
}
// ReverseLookup is used to perform a reverse DNS Lookup
// using an IPv4 or IPv6 address.
// Query Type is set to PTR, Query Class is set to IN.
// Query Names must be formatted in in-addr.arpa. or ip6.arpa format.
func (app *App) ReverseLookup() {
app.QueryFlags.QTypes = []string{"PTR"}
app.QueryFlags.QClasses = []string{"IN"}
formattedNames := make([]string, 0, len(app.QueryFlags.QNames))
for _, n := range app.QueryFlags.QNames {
addr, err := dns.ReverseAddr(n)
if err != nil {
app.Logger.WithError(err).Error("error formatting address")
app.Logger.Exit(2)
}
formattedNames = append(formattedNames, addr)
}
app.QueryFlags.QNames = formattedNames
}

View file

@ -3,16 +3,20 @@ package models
import "time"
const (
// DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS
// DefaultTLSPort specifies the default port for a DNS server connecting over TCP over TLS.
DefaultTLSPort = "853"
// DefaultUDPPort specifies the default port for a DNS server connecting over UDP
// DefaultUDPPort specifies the default port for a DNS server connecting over UDP.
DefaultUDPPort = "53"
// DefaultTCPPort specifies the default port for a DNS server connecting over TCP
// DefaultTCPPort specifies the default port for a DNS server connecting over TCP.
DefaultTCPPort = "53"
// DefaultDOQPort specifies the default port for a DNS server connecting over DNS over QUIC.
DefaultDOQPort = "853"
UDPResolver = "udp"
DOHResolver = "doh"
TCPResolver = "tcp"
DOTResolver = "dot"
DNSCryptResolver = "dnscrypt"
DOQResolver = "doq"
)
// QueryFlags is used store the query params
@ -29,7 +33,12 @@ type QueryFlags struct {
Color bool `koanf:"color" json:"-"`
DisplayTimeTaken bool `koanf:"time" json:"-"`
ShowJSON bool `koanf:"json" json:"-"`
ShortOutput bool `koanf:"short" short:"-"`
UseSearchList bool `koanf:"search" json:"-"`
ReverseLookup bool `koanf:"reverse" reverse:"-"`
Strategy string `koanf:"strategy" strategy:"-"`
InsecureSkipVerify bool `koanf:"skip-hostname-verification" skip-hostname-verification:"-"`
TLSHostname string `koanf:"tls-hostname" tls-hostname:"-"`
}
// Nameserver represents the type of Nameserver

View file

@ -1,6 +1,9 @@
package resolvers
import (
"crypto/tls"
"time"
"github.com/miekg/dns"
"github.com/sirupsen/logrus"
)
@ -14,8 +17,6 @@ type ClassicResolver struct {
// ClassicResolverOpts holds options for setting up a Classic resolver.
type ClassicResolverOpts struct {
IPv4Only bool
IPv6Only bool
UseTLS bool
UseTCP bool
}
@ -32,15 +33,20 @@ func NewClassicResolver(server string, classicOpts ClassicResolverOpts, resolver
net = "tcp"
}
if classicOpts.IPv4Only {
if resolverOpts.UseIPv4 {
net = net + "4"
}
if classicOpts.IPv6Only {
if resolverOpts.UseIPv6 {
net = net + "6"
}
if classicOpts.UseTLS {
net = net + "-tls"
// Provide extra TLS config for doing/skipping hostname verification.
client.TLSConfig = &tls.Config{
ServerName: resolverOpts.TLSHostname,
InsecureSkipVerify: resolverOpts.InsecureSkipVerify,
}
}
client.Net = net
@ -65,11 +71,33 @@ func (r *ClassicResolver) Lookup(question dns.Question) (Response, error) {
"ndots": r.resolverOptions.Ndots,
"nameserver": r.server,
}).Debug("Attempting to resolve")
in, rtt, err := r.client.Exchange(&msg, r.server)
// Since the library doesn't include tcp.Dial time,
// it's better to not rely on `rtt` provided here and calculate it ourselves.
now := time.Now()
in, _, err := r.client.Exchange(&msg, r.server)
if err != nil {
return rsp, err
}
// pack questions in output.
// In case the response size exceeds 512 bytes (can happen with lot of TXT records),
// fallback to TCP as with UDP the response is truncated. Fallback mechanism is in-line with `dig`.
if in.Truncated {
switch r.client.Net {
case "udp":
r.client.Net = "tcp"
case "udp4":
r.client.Net = "tcp4"
case "udp6":
r.client.Net = "tcp6"
default:
r.client.Net = "tcp"
}
r.resolverOptions.Logger.WithField("protocol", r.client.Net).Debug("Response truncated; retrying now")
return r.Lookup(question)
}
// Pack questions in output.
for _, q := range msg.Question {
ques := Question{
Name: q.Name,
@ -78,13 +106,15 @@ func (r *ClassicResolver) Lookup(question dns.Question) (Response, error) {
}
rsp.Questions = append(rsp.Questions, ques)
}
// get the authorities and answers.
rtt := time.Since(now)
// Get the authorities and answers.
output := parseMessage(in, rtt, r.server)
rsp.Authorities = output.Authorities
rsp.Answers = output.Answers
if len(output.Answers) > 0 {
// stop iterating the searchlist.
// Stop iterating the searchlist.
break
}
}

83
pkg/resolvers/dnscrypt.go Normal file
View file

@ -0,0 +1,83 @@
package resolvers
import (
"time"
"github.com/ameshkov/dnscrypt/v2"
"github.com/miekg/dns"
"github.com/sirupsen/logrus"
)
// DNSCryptResolver represents the config options for setting up a Resolver.
type DNSCryptResolver struct {
client *dnscrypt.Client
server string
resolverInfo *dnscrypt.ResolverInfo
resolverOptions Options
}
// DNSCryptResolverOpts holds options for setting up a DNSCrypt resolver.
type DNSCryptResolverOpts struct {
UseTCP bool
}
// NewDNSCryptResolver accepts a list of nameservers and configures a DNS resolver.
func NewDNSCryptResolver(server string, dnscryptOpts DNSCryptResolverOpts, resolverOpts Options) (Resolver, error) {
net := "udp"
if dnscryptOpts.UseTCP {
net = "tcp"
}
client := &dnscrypt.Client{Net: net, Timeout: resolverOpts.Timeout, UDPSize: 4096}
resolverInfo, err := client.Dial(server)
if err != nil {
return nil, err
}
return &DNSCryptResolver{
client: client,
resolverInfo: resolverInfo,
server: resolverInfo.ServerAddress,
resolverOptions: resolverOpts,
}, nil
}
// Lookup takes a dns.Question and sends them to DNS Server.
// It parses the Response from the server in a custom output format.
func (r *DNSCryptResolver) Lookup(question dns.Question) (Response, error) {
var (
rsp Response
messages = prepareMessages(question, r.resolverOptions.Ndots, r.resolverOptions.SearchList)
)
for _, msg := range messages {
r.resolverOptions.Logger.WithFields(logrus.Fields{
"domain": msg.Question[0].Name,
"ndots": r.resolverOptions.Ndots,
"nameserver": r.server,
}).Debug("Attempting to resolve")
now := time.Now()
in, err := r.client.Exchange(&msg, r.resolverInfo)
if err != nil {
return rsp, err
}
rtt := time.Since(now)
// pack questions in output.
for _, q := range msg.Question {
ques := Question{
Name: q.Name,
Class: dns.ClassToString[q.Qclass],
Type: dns.TypeToString[q.Qtype],
}
rsp.Questions = append(rsp.Questions, ques)
}
// get the authorities and answers.
output := parseMessage(in, rtt, r.server)
rsp.Authorities = output.Authorities
rsp.Answers = output.Answers
if len(output.Answers) > 0 {
// stop iterating the searchlist.
break
}
}
return rsp, nil
}

View file

@ -2,6 +2,7 @@ package resolvers
import (
"bytes"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
@ -64,10 +65,29 @@ func (r *DOHResolver) Lookup(question dns.Question) (Response, error) {
if err != nil {
return rsp, err
}
if resp.StatusCode == http.StatusMethodNotAllowed {
url, err := url.Parse(r.server)
if err != nil {
return rsp, err
}
url.RawQuery = fmt.Sprintf("dns=%v", base64.RawURLEncoding.EncodeToString(b))
resp, err = r.client.Get(url.String())
if err != nil {
return rsp, err
}
}
if resp.StatusCode != http.StatusOK {
return rsp, fmt.Errorf("error from nameserver %s", resp.Status)
}
rtt := time.Since(now)
// if debug, extract the response headers
if r.resolverOptions.Logger.IsLevelEnabled(logrus.DebugLevel) {
for header, value := range resp.Header {
r.resolverOptions.Logger.WithFields(logrus.Fields{
header: value,
}).Debug("DOH response header")
}
}
// extract the binary response in DNS Message.
body, err := ioutil.ReadAll(resp.Body)
if err != nil {

130
pkg/resolvers/doq.go Normal file
View file

@ -0,0 +1,130 @@
package resolvers
import (
"crypto/tls"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"time"
"github.com/miekg/dns"
"github.com/quic-go/quic-go"
"github.com/sirupsen/logrus"
)
// DOQResolver represents the config options for setting up a DOQ based resolver.
type DOQResolver struct {
tls *tls.Config
server string
resolverOptions Options
}
// NewDOQResolver accepts a nameserver address and configures a DOQ based resolver.
func NewDOQResolver(server string, resolverOpts Options) (Resolver, error) {
return &DOQResolver{
tls: &tls.Config{
NextProtos: []string{"doq"},
},
server: server,
resolverOptions: resolverOpts,
}, nil
}
// Lookup takes a dns.Question and sends them to DNS Server.
// It parses the Response from the server in a custom output format.
func (r *DOQResolver) Lookup(question dns.Question) (Response, error) {
var (
rsp Response
messages = prepareMessages(question, r.resolverOptions.Ndots, r.resolverOptions.SearchList)
)
session, err := quic.DialAddr(r.server, r.tls, nil)
if err != nil {
return rsp, err
}
defer session.CloseWithError(quic.ApplicationErrorCode(quic.NoError), "")
for _, msg := range messages {
r.resolverOptions.Logger.WithFields(logrus.Fields{
"domain": msg.Question[0].Name,
"ndots": r.resolverOptions.Ndots,
"nameserver": r.server,
}).Debug("Attempting to resolve")
// ref: https://www.rfc-editor.org/rfc/rfc9250.html#name-dns-message-ids
msg.Id = 0
// get the DNS Message in wire format.
var b []byte
b, err = msg.Pack()
if err != nil {
return rsp, err
}
now := time.Now()
var stream quic.Stream
stream, err = session.OpenStream()
if err != nil {
return rsp, err
}
var msgLen = uint16(len(b))
var msgLenBytes = []byte{byte(msgLen >> 8), byte(msgLen & 0xFF)}
_, err = stream.Write(msgLenBytes)
if err != nil {
return rsp, err
}
// Make a QUIC request to the DNS server with the DNS message as wire format bytes in the body.
_, err = stream.Write(b)
if err != nil {
return rsp, err
}
err = stream.SetDeadline(time.Now().Add(r.resolverOptions.Timeout))
if err != nil {
return rsp, err
}
var buf []byte
buf, err = io.ReadAll(stream)
if err != nil {
if errors.Is(err, os.ErrDeadlineExceeded) {
return rsp, fmt.Errorf("timeout")
}
return rsp, err
}
rtt := time.Since(now)
_ = stream.Close()
packetLen := binary.BigEndian.Uint16(buf[:2])
if packetLen != uint16(len(buf[2:])) {
return rsp, fmt.Errorf("packet length mismatch")
}
err = msg.Unpack(buf[2:])
if err != nil {
return rsp, err
}
// pack questions in output.
for _, q := range msg.Question {
ques := Question{
Name: q.Name,
Class: dns.ClassToString[q.Qclass],
Type: dns.TypeToString[q.Qtype],
}
rsp.Questions = append(rsp.Questions, ques)
}
// get the authorities and answers.
output := parseMessage(&msg, rtt, r.server)
rsp.Authorities = output.Authorities
rsp.Answers = output.Answers
if len(output.Answers) > 0 {
// stop iterating the searchlist.
break
}
}
return rsp, nil
}

View file

@ -3,21 +3,25 @@ package resolvers
import (
"time"
"git.zio.sh/astra/doggo/pkg/models"
"github.com/miekg/dns"
"github.com/mr-karan/doggo/pkg/models"
"github.com/sirupsen/logrus"
)
// Options represent a set of common options
// to configure a Resolver.
type Options struct {
Logger *logrus.Logger
Nameservers []models.Nameserver
UseIPv4 bool
UseIPv6 bool
SearchList []string
Ndots int
Timeout time.Duration
Logger *logrus.Logger
Strategy string
InsecureSkipVerify bool
TLSHostname string
}
// Resolver implements the configuration for a DNS
@ -67,18 +71,13 @@ type Authority struct {
// LoadResolvers loads differently configured
// resolvers based on a list of nameserver.
func LoadResolvers(opts Options) ([]Resolver, error) {
var resolverOpts = Options{
Timeout: opts.Timeout,
Ndots: opts.Ndots,
SearchList: opts.SearchList,
Logger: opts.Logger,
}
// for each nameserver, initialise the correct resolver
// For each nameserver, initialise the correct resolver.
rslvrs := make([]Resolver, 0, len(opts.Nameservers))
for _, ns := range opts.Nameservers {
if ns.Type == models.DOHResolver {
opts.Logger.Debug("initiating DOH resolver")
rslvr, err := NewDOHResolver(ns.Address, resolverOpts)
rslvr, err := NewDOHResolver(ns.Address, opts)
if err != nil {
return rslvrs, err
}
@ -88,11 +87,9 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
opts.Logger.Debug("initiating DOT resolver")
rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: true,
UseTCP: true,
}, resolverOpts)
}, opts)
if err != nil {
return rslvrs, err
@ -103,11 +100,9 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
opts.Logger.Debug("initiating TCP resolver")
rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: false,
UseTCP: true,
}, resolverOpts)
}, opts)
if err != nil {
return rslvrs, err
}
@ -117,11 +112,28 @@ func LoadResolvers(opts Options) ([]Resolver, error) {
opts.Logger.Debug("initiating UDP resolver")
rslvr, err := NewClassicResolver(ns.Address,
ClassicResolverOpts{
IPv4Only: opts.UseIPv4,
IPv6Only: opts.UseIPv6,
UseTLS: false,
UseTCP: false,
}, resolverOpts)
}, opts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
if ns.Type == models.DNSCryptResolver {
opts.Logger.Debug("initiating DNSCrypt resolver")
rslvr, err := NewDNSCryptResolver(ns.Address,
DNSCryptResolverOpts{
UseTCP: false,
}, opts)
if err != nil {
return rslvrs, err
}
rslvrs = append(rslvrs, rslvr)
}
if ns.Type == models.DOQResolver {
opts.Logger.Debug("initiating DOQ resolver")
rslvr, err := NewDOQResolver(ns.Address, opts)
if err != nil {
return rslvrs, err
}