diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 29fc64a..28db573 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,9 +5,6 @@ on: tags: - "*" -env: - REGISTRY: ghcr.io - jobs: goreleaser: runs-on: ubuntu-latest @@ -19,14 +16,17 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.19 - - name: Log in to the Container registry - uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + go-version: 1.16 + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 with: - registry: ${{ env.REGISTRY }} + registry: ghcr.io username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - + password: ${{ secrets.GH_GORELEASER_TOKEN }} + - name: Install Snapcraft and Log In + uses: samuelmeuli/action-snapcraft@v1 + with: + snapcraft_token: ${{ secrets.SNAPCRAFT_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.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GH_GORELEASER_TOKEN }} diff --git a/.gitignore b/.gitignore index 4d06b6f..2bdbba7 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,3 @@ vendor/ config.yml .DS_Store bin/* -node_modules \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml index 49159b4..2b3b359 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -17,7 +17,7 @@ builds: - 7 ldflags: - -s -w -X "main.buildVersion={{ .Tag }} ({{ .ShortCommit }} {{ .Date }})" - dir: ./cmd/doggo/ + dir: ./cmd/doggo/cli/ - binary: doggo-api.bin id: api @@ -33,62 +33,64 @@ builds: - 7 ldflags: - -s -w -X "main.buildVersion={{ .Tag }} ({{ .ShortCommit }} {{ .Date }})" - dir: ./cmd/api/ + dir: ./cmd/doggo/api/ archives: - format: tar.gz files: - README.md - LICENSE - - completions/ + +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 dockers: - image_templates: - - "ghcr.io/mr-karan/doggo:{{ .Tag }}" - - "ghcr.io/mr-karan/doggo:latest" - id: doggo - # IDs to filter the binaries/packages. - ids: - - cli + - "ghcr.io/mr-karan/doggo-cli:{{ .Tag }}" + - "ghcr.io/mr-karan/doggo-cli:latest" + binaries: + - doggo dockerfile: Dockerfile-cli build_flag_templates: - "--build-arg" - "ARCH=amd64" - image_templates: - - "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 + - "ghcr.io/mr-karan/doggo-cli:{{ .Tag }}-arm64v8" + - "ghcr.io/mr-karan/doggo-cli:latest-arm64v8" + binaries: + - doggo 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" - # 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 + - 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 diff --git a/Makefile b/Makefile index fb8eb83..0b039c9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CLI_BIN := ./bin/doggo.bin +CLI_BIN := ./bin/doggo-cli.bin API_BIN := ./bin/doggo-api.bin HASH := $(shell git rev-parse --short HEAD) @@ -7,11 +7,12 @@ VERSION := ${HASH} .PHONY: build-cli build-cli: - go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/ + go build -o ${CLI_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/cli/ .PHONY: build-api build-api: - go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/api/ + go build -o ${API_BIN} -ldflags="-X 'main.buildVersion=${VERSION}' -X 'main.buildDate=${BUILD_DATE}'" ./cmd/doggo/api/ + .PHONY: build build: build-api build-cli diff --git a/README.md b/README.md index d2ae781..a637ebc 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,13 @@
🐶 Command-line DNS client for humans
-
- doggo.mrkaran.dev
---
-**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.
+**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.
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**.
@@ -24,28 +22,23 @@ 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://git.zio.sh/astra/doggo/releases) section.
+You can grab the latest binaries for Linux, MacOS and Windows from the [Releases](https://github.com/mr-karan/doggo/releases) section.
-For eg, to pull the latest `linux-amd64` binary:
+For eg, to pull the latest Linux binary:
```shell
$ cd "$(mktemp -d)"
-$ curl -sL "https://git.zio.sh/astra/doggo/releases/download/v0.3.7/doggo_0.3.7_linux_amd64.tar.gz" | tar xz
+$ curl -sL "https://github.com/mr-karan/doggo/releases/download/v0.2.0/doggo_0.2.0_linux_amd64.tar.gz" | tar xz
$ mv doggo /usr/local/bin
# doggo should be available now in your $PATH
$ doggo
@@ -65,36 +58,24 @@ 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`
-### Package Managers
+### Using snap
-#### Homebrew
+[](https://snapcraft.io/doggo)
-Install via [Homebrew](https://brew.sh/)
-
-```bash
-$ brew install doggo
+```sh
+$ sudo snap install doggo
```
-#### Arch
-
-```bash
-yay -S doggo-bin
-```
-
-#### Scoop
-
-Install via [Scoop](https://scoop.sh/)
-
-```bash
-scoop 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`.
### From Source
You need to have `go` installed in your system.
```bash
-$ go install git.zio.sh/astra/doggo/cmd/doggo@latest
+$ go get github.com/mr-karan/doggo/cmd/doggo
```
The binary will be available at `$GOPATH/bin/doggo`.
@@ -209,10 +190,6 @@ 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
@@ -227,14 +204,11 @@ 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.
+ --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.
```
@@ -245,7 +219,6 @@ 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.
```
---
@@ -258,4 +231,4 @@ For now I am focussing more on [planned features](TODO.md) for a **stable** v1.0
## License
-[LICENSE](./LICENSE)
+[LICENSE](LICENSE)
diff --git a/TODO.md b/TODO.md
index 30cca2f..30effea 100644
--- a/TODO.md
+++ b/TODO.md
@@ -54,16 +54,14 @@
# Future Release
- [ ] Support obscure protocol tweaks in `dig`
+- [ ] Read from file with `-f`
- [x] Support more DNS Record Types
-- [x] Shell completions
- - [x] zsh
- - [x] fish
+- [ ] Shell completions
+ - [ ] bash
+ - [ ] zsh
+ - [ ] 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))
diff --git a/cmd/api/assets/dark.css b/cmd/api/assets/dark.css
deleted file mode 100644
index 4e4777d..0000000
--- a/cmd/api/assets/dark.css
+++ /dev/null
@@ -1,48 +0,0 @@
-: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;
-}
\ No newline at end of file
diff --git a/cmd/api/assets/main.js b/cmd/api/assets/main.js
deleted file mode 100644
index dc405a2..0000000
--- a/cmd/api/assets/main.js
+++ /dev/null
@@ -1,90 +0,0 @@
-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();
- }
- };
-})();
\ No newline at end of file
diff --git a/cmd/api/assets/style.css b/cmd/api/assets/style.css
deleted file mode 100644
index 84b2194..0000000
--- a/cmd/api/assets/style.css
+++ /dev/null
@@ -1,201 +0,0 @@
-: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;
- }
-}
\ No newline at end of file
diff --git a/cmd/api/index.html b/cmd/api/index.html
deleted file mode 100644
index c5de849..0000000
--- a/cmd/api/index.html
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
- Oops! Found no records for this query.
+{{apiErrorMessage}}
+