Introducing Doggo

I’ll take the opportunity of adding the first post to this new category :smiley:

A few months back I worked on a side project Doggo which is a command line DNS utility (much like dig). The output of dig is a bit noisy and the flag usage is not really straightforward (atleast without referring to Man pages). I use dig a lot at my work, and also happened to chance upon another project (written in Rust) dog, which was the primary motivation for me to write a similar tool in Golang.

It supports a wide range of DNS Transport protocols (DoH, DoT, DNSCrypt etc), colored output on Terminal, JSON reports etc.

It’s available as a Binary, Docker Image, REST API and a frontend tool as well (which @knadh helped me with) .

I’d love any kind of feedback + feature requests on this :slight_smile:

7 Likes

Awesome!

Going through the source code, it is very interesting to see how hard it is to find the system nameservers on windows.

Doggo seems to be working slighly differently compared to dog and dig when it comes to reading the system nameservers. Doggo seems to be picking all the entries while the other tools pick only the first one.

$ doggo fossunited.org
NAME           	TYPE	CLASS	TTL  	ADDRESS     	NAMESERVER
fossunited.org.	A   	IN   	2327s	68.183.89.27	9.9.9.9:53
fossunited.org.	A   	IN   	2568s	68.183.89.27	149.112.112.112:53

$ dog fossunited.org
A fossunited.org. 37m48s   68.183.89.27

$ dig  fossunited.org
...
fossunited.org.		2195	IN	A	68.183.89.27
...

On mac os x, when I remove all the name servers, the system replaces the nameservers with the nameserver from the DHCP. The nameserver that got are:

$ cat /etc/resolv.conf
nameserver 192.168.0.1
nameserver 0.0.0.0

The entry 0.0.0.0 is an errounous entry coming from my router. That is breaking Doggo, but not the other tools. It may be because they are picking only the first entry.

$ doggo fossunited.org
ERROR[2021-05-17T20:19:20+05:30] error looking up DNS records                  
error="read udp 127.0.0.1:58751->127.0.0.1:53: read: connection refused"

$ dog fossunited.org
A fossunited.org. 32m23s   68.183.89.27

$ dig fossunited.org
fossunited.org.		1929	IN	A	68.183.89.27

Appaently, routers sending 0.0.0.0 as nameserver is a well known issue and resolve.conf documentation suggest that it supports a name_server_blacklist field.

name_server_blacklist

A list of name servers to be removed from consideration. The default is 0.0.0.0 as some faulty
routers send it via DHCP. To remove a block, you can use 192.168.*

resolvconf.conf(5) — openresolv — Debian testing — Debian Manpages

However, showing duplicate results for each system name server doesn’t sound like a good idea. The user is most likely to use the tool to troubleshoot a domain rather than nameserver. If it were the latter, there is always an option to specify the nameserver as command-line arguments.

What do you think?

1 Like

Yep, that’s intentional.

Hm, well I’ve had to actually deal with DNS server issues in the past and that’s why I thought it’ll be a nice idea to query a DNS record with all nameservers.

Just to illustrate a simple point where this could be useful, consider you’ve a Split DNS setup where a record like mycorp.xyz resolves to 2 different A records (on 2 different nameservers). Doing doggo mycorp.xyz would actually be beneficial here, since you could see both the records in one command.

Appaently, routers sending 0.0.0.0 as nameserver is a well known issue and resolve.conf documentation suggest that it supports a name_server_blacklist field.

This is interesting, TIL :slight_smile:

However, I think I can push a patch for this, where doggo should not fail entirely if it failed for just one nameserver. I can probably silently fail in the default scenario, which will make it look like it works like dig/dog and if verbose mode is enabled, the user could see a proper error message. Does that sound fine?

Thanks for looking into this, appreciate your feedback!

1 Like

It was actually a simple fix in the codebase, that it doesn’t look like a legit fix :smiley:

How it behaves in case of an invalid entry in /etc/resolv.conf:

❯ ./bin/doggo-cli.bin github.com
ERROR[2021-05-18T19:07:56+05:30] error looking up DNS records                  error="read udp 192.168.1.5:47472->100.0.0.1:53: i/o timeout"
NAME            TYPE    CLASS   TTL     ADDRESS         NAMESERVER   
github.com.     A       IN      30s     13.234.210.38   127.0.0.1:53

I thought about silently failing, but I think verbose logging should actually be only for more verbose/debugging information, errors are not that.

And about picking up just one nameserver from the resolvconf, so dig actually tries to pick the second nameserver only if the first nameserver gave a SERVFAIL response.

Consider:

nameserver 100.0.0.1
nameserver 1.1.1.1
❯ dig +noall +answer github.com
github.com.             48      IN      A       13.234.210.38

So despite the first entry being erroneous, it actually picked the second and resolved.

I’d say it’s useful, but honestly I don’t see a strong reason as to why doggo should follow the same approach. One downside I can see is that if you have 5 nameservers in your /etc/resolv.conf, each having a query timeout of 5s and let’s say 4 nameservers are down, then the minimum response time would be 20s…which can be quite irritating. But atleast doggo will show the problem with the nameserver, unlike dig which silently jumps to next good nameserver.

So I think weighing both sides, the current behaviour of doggo seems alright IMHO :slight_smile:

An update to this: doggo now supports an additional --strategy flag: https://github.com/mr-karan/doggo/commit/7619cbdeb0b6744e8c989fc866173874fcf0a430

  • --strategy=all is the default current behaviour to maintain backward compat
  • --strategy=first picks up only the first nameserver from /etc/resolv.conf which is what you’d need here probably @Anand
  • --strategy=random randomly picks one if you’ve multiple nameservers in /etc/resolv.conf
1 Like