chore: add docs
parent
81a04b6d93
commit
05914cca9e
189
README.md
189
README.md
|
@ -1,6 +1,189 @@
|
||||||
# doggo
|
<!-- PROJECT LOGO -->
|
||||||
|
<br />
|
||||||
|
<p align="center">
|
||||||
|
<h2 align="center">doggo</h2>
|
||||||
|
<p align="center">
|
||||||
|
🐶 <i>Command-line DNS client for humans</i>
|
||||||
|
</p>
|
||||||
|
<img src="www/static/usage.png" alt="doggo CLI usage">
|
||||||
|
</p>
|
||||||
|
|
||||||
_Command-line DNS client written in Golang_
|
---
|
||||||
|
|
||||||
![](www/static/main.png)
|
`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 oppurtunity
|
||||||
|
to experiment with writing a DNS Client from scratch in `Go` myself. Hence the name `dog` +`go` => `doggo`.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Human readable output - Supports colors and tabular format.
|
||||||
|
- Supports JSON format - useful for writing scripts.
|
||||||
|
- Has support for multiple transport protocols:
|
||||||
|
- DNS over **HTTPS** (DoH)
|
||||||
|
- DNS over **TLS** (DoT)
|
||||||
|
- DNS over **TCP**
|
||||||
|
- DNS over **UDP**
|
||||||
|
- Supports **ndots** and **search** configurations from `resolv.conf` or command-line arguments.
|
||||||
|
- Supports multiple resolvers in one go.
|
||||||
|
- Supports IPv4 **and** IPv6 _both_.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Binary (Recommended)
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
|
||||||
|
### Snap
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
**Do a simple DNS Lookup for `mrkaran.dev`**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ doggo mrkaran.dev
|
||||||
|
NAME TYPE CLASS TTL ADDRESS NAMESERVER
|
||||||
|
mrkaran.dev. A IN 20s 13.250.205.9 127.0.0.1:53
|
||||||
|
mrkaran.dev. A IN 20s 206.189.89.118 127.0.0.1:53
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query MX records for `github.com` using `9.9.9.9` resolver**
|
||||||
|
|
||||||
|
```
|
||||||
|
doggo MX github.com @9.9.9.9
|
||||||
|
NAME TYPE CLASS TTL ADDRESS NAMESERVER
|
||||||
|
github.com. MX IN 3600s 10 alt3.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 5 alt1.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 10 alt4.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 5 alt2.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 1 aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
```
|
||||||
|
|
||||||
|
or using _named parameters_:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ doggo -t MX -n 9.9.9.9 github.com
|
||||||
|
NAME TYPE CLASS TTL ADDRESS NAMESERVER
|
||||||
|
github.com. MX IN 3600s 10 alt3.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 5 alt1.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 10 alt4.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 5 alt2.aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
github.com. MX IN 3600s 1 aspmx.l.google.com. 9.9.9.9:53
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query DNS records for archive.org using Cloudflare DoH resolver**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ doggo archive.org @https://cloudflare-dns.com/dns-query
|
||||||
|
NAME TYPE CLASS TTL ADDRESS NAMESERVER
|
||||||
|
archive.org. A IN 41s 207.241.224.2 https://cloudflare-dns.com/dns-query
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query DNS records for internetfreedom.in with JSON output**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ doggo internetfreedom.in --json | jq
|
||||||
|
{
|
||||||
|
"responses": {
|
||||||
|
"answers": [
|
||||||
|
{
|
||||||
|
"name": "internetfreedom.in.",
|
||||||
|
"type": "A",
|
||||||
|
"class": "IN",
|
||||||
|
"ttl": "22s",
|
||||||
|
"address": "104.27.158.96",
|
||||||
|
"rtt": "37ms",
|
||||||
|
"nameserver": "127.0.0.1:53"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "internetfreedom.in.",
|
||||||
|
"type": "A",
|
||||||
|
"class": "IN",
|
||||||
|
"ttl": "22s",
|
||||||
|
"address": "104.27.159.96",
|
||||||
|
"rtt": "37ms",
|
||||||
|
"nameserver": "127.0.0.1:53"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "internetfreedom.in.",
|
||||||
|
"type": "A",
|
||||||
|
"class": "IN",
|
||||||
|
"ttl": "22s",
|
||||||
|
"address": "172.67.202.77",
|
||||||
|
"rtt": "37ms",
|
||||||
|
"nameserver": "127.0.0.1:53"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"queries": [
|
||||||
|
{
|
||||||
|
"name": "internetfreedom.in.",
|
||||||
|
"type": "A",
|
||||||
|
"class": "IN"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Query DNS records for duckduckgo.com and show RTT (Round Trip Time)**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ doggo duckduckgo.com --time
|
||||||
|
NAME TYPE CLASS TTL ADDRESS NAMESERVER TIME TAKEN
|
||||||
|
duckduckgo.com. A IN 30s 40.81.94.43 127.0.0.1:53 45ms
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command-line Arguments
|
||||||
|
|
||||||
|
![](www/static/help.png)
|
||||||
|
|
||||||
|
### Transport Options
|
||||||
|
|
||||||
|
URL scheme of the server is used to identify which resolver to use for lookups. If no scheme is specified, defaults to `udp`.
|
||||||
|
|
||||||
|
```
|
||||||
|
@udp:// eg: @1.1.1.1 initiates a UDP resolver for 1.1.1.1:53.
|
||||||
|
@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.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Query Options
|
||||||
|
|
||||||
|
```
|
||||||
|
-q, --query=HOSTNAME Hostname to query the DNS records for (eg mrkaran.dev).
|
||||||
|
-t, --type=TYPE Type of the DNS Record (A, MX, NS etc).
|
||||||
|
-n, --nameserver=ADDR Address of a specific nameserver to send queries to (9.9.9.9, 8.8.8.8 etc).
|
||||||
|
-c, --class=CLASS Network class of the DNS record (IN, CH, HS etc).
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resolver Options
|
||||||
|
|
||||||
|
```
|
||||||
|
--ndots=INT Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever 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.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Output Options
|
||||||
|
|
||||||
|
```
|
||||||
|
-J, --json Format the output as JSON.
|
||||||
|
--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.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
I'm open to accept feature requests and/or issues. I understand `doggo` is a very new DNS Client in the town and there might be some edge cases I am not handling. Please feel free to open issues if you ever come across such a case.
|
||||||
|
For now I am focussing more on [planned features](TODO.md) for a **stable** v1.0 release _soon_.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[LICENSE](LICENSE)
|
||||||
|
|
22
TODO.md
22
TODO.md
|
@ -39,25 +39,18 @@
|
||||||
- [x] Remove urfave/cli in favour of `pflag + koanf`
|
- [x] Remove urfave/cli in favour of `pflag + koanf`
|
||||||
- [x] Flags - Remove uneeded ones
|
- [x] Flags - Remove uneeded ones
|
||||||
|
|
||||||
## Tests
|
|
||||||
- [ ] Add tests for Resolvers.
|
|
||||||
- [ ] Add tests for CLI Output.
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
- [ ] README
|
- [x] README
|
||||||
- [ ] Usage
|
- [x] Usage
|
||||||
- [ ] Installation
|
- [x] Installation
|
||||||
- [ ] Features
|
- [x] Features
|
||||||
- [ ] Mkdocs init project
|
|
||||||
- [ ] Custom Index (Landing Page)
|
|
||||||
|
|
||||||
## Release Checklist
|
## Release Checklist
|
||||||
- [ ] Goreleaser
|
- [ ] Goreleaser
|
||||||
- [ ] Snap
|
- [ ] Snap
|
||||||
- [ ] Homebrew
|
- [ ] Homebrew
|
||||||
- [ ] ARM
|
|
||||||
- [ ] Docker
|
- [ ] Docker
|
||||||
|
|
||||||
---
|
---
|
||||||
# Future Release
|
# Future Release
|
||||||
|
|
||||||
|
@ -70,4 +63,7 @@
|
||||||
- [ ] zsh
|
- [ ] zsh
|
||||||
- [ ] fish
|
- [ ] fish
|
||||||
- [ ] Support non RFC Compliant DOH Google response (_ugh_)
|
- [ ] Support non RFC Compliant DOH Google response (_ugh_)
|
||||||
|
- [ ] Add tests for Resolvers.
|
||||||
|
- [ ] Add tests for CLI Output.
|
||||||
|
- [ ] Mkdocs init project
|
||||||
|
- [ ] Custom Index (Landing Page)
|
|
@ -40,7 +40,7 @@ func main() {
|
||||||
// Resolver Options
|
// Resolver Options
|
||||||
f.Int("timeout", 5, "Sets the timeout for a query to T seconds. The default timeout is 5 seconds.")
|
f.Int("timeout", 5, "Sets the timeout for a query to T seconds. The default timeout is 5 seconds.")
|
||||||
f.Bool("search", true, "Use the search list provided in resolv.conf. It sets the `ndots` parameter as well unless overriden by `ndots` flag.")
|
f.Bool("search", true, "Use the search list provided in resolv.conf. It sets the `ndots` parameter as well unless overriden by `ndots` flag.")
|
||||||
f.Int("ndots", 1, "Specify the ndots paramter. Default value is taken from resolv.conf and fallbacks to 1 if ndots statement is missing in resolv.conf")
|
f.Int("ndots", 0, "Specify the ndots paramter. 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("ipv4", "4", false, "Use IPv4 only")
|
||||||
f.BoolP("ipv6", "6", false, "Use IPv6 only")
|
f.BoolP("ipv6", "6", false, "Use IPv6 only")
|
||||||
|
|
||||||
|
|
47
cmd/help.go
47
cmd/help.go
|
@ -13,32 +13,48 @@ var appHelpTextTemplate = `{{ "NAME" | color "" "heading" }}:
|
||||||
{{ .Name | color "green" "bold" }} 🐶 {{.Description}}
|
{{ .Name | color "green" "bold" }} 🐶 {{.Description}}
|
||||||
|
|
||||||
{{ "USAGE" | color "" "heading" }}:
|
{{ "USAGE" | color "" "heading" }}:
|
||||||
{{ .Name | color "green" "" }} [--] {{ "[query options]" | color "yellow" "" }} {{ "[arguments...]" | color "cyan" "" }}
|
{{ .Name | color "green" "bold" }} [--] {{ "[query options]" | color "yellow" "" }} {{ "[arguments...]" | color "cyan" "" }}
|
||||||
|
|
||||||
{{ "VERSION" | color "" "heading" }}:
|
{{ "VERSION" | color "" "heading" }}:
|
||||||
{{.Version | color "red" "" }} - {{.Date | color "red" ""}}
|
{{.Version | color "red" "" }} - {{.Date | color "red" ""}}
|
||||||
|
|
||||||
{{ "EXAMPLES" | color "" "heading" }}:
|
{{ "EXAMPLES" | color "" "heading" }}:
|
||||||
{{ .Name | color "green" "" }} {{ "mrkaran.dev" | color "cyan" "" }} Query a domain using defaults
|
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev" | color "cyan" "" }} Query a domain using defaults.
|
||||||
{{ .Name | color "green" "" }} {{ "mrkaran.dev CNAME" | color "cyan" "" }} Looks up for a CNAME record
|
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev CNAME" | color "cyan" "" }} Looks up for a CNAME record.
|
||||||
{{ .Name | color "green" "" }} {{ "mrkaran.dev MX @9.9.9.9" | color "cyan" "" }} Uses a custom DNS resolver
|
{{ .Name | color "green" "bold" }} {{ "mrkaran.dev MX @9.9.9.9" | color "cyan" "" }} Uses a custom DNS resolver.
|
||||||
{{ .Name | color "green" "" }} {{"-q mrkaran.dev -t MX -n 1.1.1.1" | color "yellow" ""}} Using named arguments
|
{{ .Name | color "green" "bold" }} {{"-q mrkaran.dev -t MX -n 1.1.1.1" | color "yellow" ""}} Using named arguments.
|
||||||
|
|
||||||
{{ "Free Form Arguments" | color "" "heading" }}:
|
{{ "Free Form Arguments" | color "" "heading" }}:
|
||||||
Supply hostnames, query types, classes without any flag. For eg:
|
Supply hostnames, query types, classes without any flag. For eg:
|
||||||
{{ .Name | color "green" "" }} {{"mrkaran.dev A @1.1.1.1" | color "cyan" "" }}
|
{{ .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.
|
||||||
|
|
||||||
|
{{"@udp://" | color "yellow" ""}} eg: @1.1.1.1 initiates a {{"UDP" | color "cyan" ""}} resolver for 1.1.1.1:53.
|
||||||
|
{{"@tcp://" | color "yellow" ""}} eg: @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: @1.1.1.1 initiates a {{"DoT" | color "cyan" ""}} resolver for 1.1.1.1:853.
|
||||||
|
|
||||||
{{ "Query Options" | color "" "heading" }}:
|
{{ "Query Options" | color "" "heading" }}:
|
||||||
{{"-q, --query=HOSTNAME" | color "yellow" ""}} Hostname to query the DNS records for
|
{{"-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 etc)
|
{{"-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, 1.1.1.1 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 etc)
|
{{"-c, --class=CLASS" | color "yellow" ""}} Network class of the DNS record ({{"IN, CH, HS" | color "cyan" ""}} etc).
|
||||||
|
|
||||||
|
{{ "Resolver Options" | color "" "heading" }}:
|
||||||
|
{{"--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.
|
||||||
|
|
||||||
{{ "Output Options" | color "" "heading" }}:
|
{{ "Output Options" | color "" "heading" }}:
|
||||||
{{"-J, --json " | color "yellow" ""}} Format the output as JSON
|
{{"-J, --json " | color "yellow" ""}} Format the output as JSON.
|
||||||
{{"--color " | color "yellow" ""}} Defaults to true. Set --color=false to disable colored output
|
{{"--color " | color "yellow" ""}} Defaults to true. Set --color=false to disable colored output.
|
||||||
{{"--debug " | color "yellow" ""}} Enable debug logging
|
{{"--debug " | color "yellow" ""}} Enable debug logging.
|
||||||
{{"--time" | color "yellow" ""}} Shows how long the response took from the server
|
{{"--time" | color "yellow" ""}} Shows how long the response took from the server.
|
||||||
`
|
`
|
||||||
|
|
||||||
func renderCustomHelp() {
|
func renderCustomHelp() {
|
||||||
|
@ -67,8 +83,7 @@ func renderCustomHelp() {
|
||||||
case "underline":
|
case "underline":
|
||||||
formatter = formatter.Add(color.Underline)
|
formatter = formatter.Add(color.Underline)
|
||||||
case "heading":
|
case "heading":
|
||||||
formatter = formatter.Add(color.Bold)
|
formatter = formatter.Add(color.Bold, color.Underline)
|
||||||
formatter = formatter.Add(color.Underline)
|
|
||||||
}
|
}
|
||||||
return formatter.SprintFunc()(str)
|
return formatter.SprintFunc()(str)
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,7 +46,7 @@ func (hub *Hub) loadNameservers() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetching system default nameserver")
|
return fmt.Errorf("error fetching system default nameserver")
|
||||||
}
|
}
|
||||||
if !hub.QueryFlags.isNdotsSet {
|
if hub.QueryFlags.Ndots == 0 {
|
||||||
hub.QueryFlags.Ndots = ndots
|
hub.QueryFlags.Ndots = ndots
|
||||||
}
|
}
|
||||||
hub.Nameservers = append(hub.Nameservers, ns...)
|
hub.Nameservers = append(hub.Nameservers, ns...)
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 224 KiB |
Binary file not shown.
Before Width: | Height: | Size: 167 KiB |
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
Loading…
Reference in New Issue