Hacker News new | past | comments | ask | show | jobs | submit login
Dog – A command-line DNS client written in Rust (github.com/ogham)
255 points by guessmyname on Nov 9, 2020 | hide | past | favorite | 81 comments



I know this is a case of using the wrong tool for the job, but about once every 3 months or so, I find myself using dig to troubleshoot an issue, only to find out I had a hosts file entry and that's why it was/wasn't working.

I've been trying to force myself to use curl --resolve rather than using hosts file entries (where it's suitable) but for some reason I just can't seem to force myself to get into the habit of getent vs dig.

What would save me wasted time is an asterisk next to an entry or a reminder at the bottom of the output (or in stderr) which indicates that there is a hosts file entry which matches, but it was "ignored" (and even what it's value is).

I understand if it's not something you want to support, but it's definitely a pain point for myself and quite a few ops people I've shoulder surfed over the years.


I use getent for passwd and groups, but didn't realize what else it could be used for, thanks!

I found this page which has some good examples for getent, if anyone is interested: https://www.commandlinefu.com/commands/using/getent


To use a single third party utility like dig that would retrieve entries from both /etc/hosts and from zone files, one could use a program like pdns_recursor with the "--export-etc-hosts=on" option.

https://doc.powerdns.com/recursor/manpages/pdns_recursor.1.h...

Assuming for example, one had HOSTS entries

   127.0.0.1 localhost
   93.184.216.34  example.com 
pdns_recursor is listening on 127.0.0.1 and /etc/resolv.conf contains namserver 127.0.0.1, then

   dig ns example.com 
should return "localhost" as the NS RR for example.com so we know the A RR came from /etc/hosts not a.iana-servers.net

Additionally, adding the "--trace=on" option will output debugging info that will tell whether the answer came from "local auth storage", e.g., /etc/hosts



I've fought a number of resolver issues over the years, where, for various reasons, the application resolves differently from client tools, or client tools resolve differently from each other. Sometimes related to hosts file entries, but those are much easier to figure out than issues related to truncated replies related to EDNS or UDP vs TCP replies, or similar. (it's been awhile, so I forget details).


I've started just editing an instance of unbound on my router for custom DNS records. I've gone as far as redirecting all my port 53 traffic to it using iptables on my router as well for those insidiously hard coded DNS servers on Google products.


Author here. Didn't expect this to show up so soon, but I'm glad people like it — I only published v0.1 on Saturday.

Over on the Rust forum I gave a brief overview of the crates and developer tools I used: https://users.rust-lang.org/t/dog-a-command-line-dns-client/...


Glad we’ve proven dogs can look up


This is great, already installed via Homebrew.

Something that puzzles me while using dig(1) is that I don't really understand the +trace output. In my mind it should be rather easy to trace a DNS request, something like: dig A google.com → etc/resolv.conf says your nameserver is X.Y.Z.T → made a query to X.Y.Z.T, it recursed → domain google.com has nameserver ns.a.b. → ADDITIONAL section told us ns.a.b is at X.C.F.G IP → made dns query to X.C.F.G, it told us it was Authoritative and gave RRs [IP1, IP2].

I never quite can get this level of clarity from dig(1), instead, "dig A google.com +trace" gives an output like this: https://gist.github.com/ahmetb/28a3853bef72fbabf4f0d8ac0712a... which makes me think like: what the hell, am I actually hitting root nameservers every time?

If your tool can help developers here, I think it's a major value add.


> what the hell, am I actually hitting root nameservers every time?

Trace hits the roots because trace is for tracing the lookups from the root nameservers through the rest of the path. It's in the man page:

  +[no]trace
    Toggle tracing of the delegation path from the root name servers for the name being looked up. ...


> made a query to X.Y.Z.T, it recursed

If it recursed, then X.Y.Z.T gave you the final response. It doesn't tell you how it arrived at that final response, and it might not even know (it only saves the final response in the cache). The output of dig +trace is the steps a recursive resolver would have to follow if it started from scratch (with a cold cache).


Oh yeah my bad, in that case, let's say "X.Y.Z.T said it doesn't support recursion".


Great work here, interesting project. I get the desire to roll your own versions of things, but personally I'd feel more comfortable using it if it used the standard community packages for dns and logging like trust-dns and tracing though.


Be honest - did you write this just for the name and resulting gags?


All I'm saying is that lookup.dog was originally going to contain a Shaun of the Dead GIF and nothing else, in the same vein as butt.holdings or cheese.singles. The DNS part came later.


Adding this to the pile of awesome tool replacements written in Rust that I use on a daily basis including ripgrep, exa, bat, and alacritty


“delta” is another one worth looking at. I like the look of “dog” a lot! Also, TIL the EUPL, which looks rather interesting.


Just took a look at all the tools you listed (besides ripgrep, as I've already been using it). Exa and bat look great! Just installed them and am looking forward to using them. I'm having a hard time convincing myself to leave iTerm for Alacritty, just for a speed boost. I've never had speed issues with iTerm, but I'm wondering if there is anything else you like about alacritty that might change my mind.


> I'm having a hard time convincing myself to leave iTerm for Alacritty, just for a speed boost.

I've never understood why anyone would want a higher-throughput terminal. Better latency I could see, but throughput? I'm not Commander Data. I can only read so fast. If my shell is dumping text at me faster than my terminal can render, it's because I catted something I shouldn't have.


I like a few things about alacritty - it handles file drag and drop better than some IMO; config takes effect immediately and has extensive options (eg arbitrary keyboard mapping); I somehow got shift-enter to work on vim which I had trouble with in other emus; it’s noticeably fast.

On the downside it has no tabs and fewer typical GUI features like right click.

If you love your emulator I wouldn’t suggest switching.


I found I had to start using tmux locally after switching to alacritty, but I count that as a good thing to learn and know.


Alacritty is more lightweight/cruft-free IMO, and cross-platform. Personally I don't want iTerm's settings menu or tabs; I do want one configuration that I can use on multiple platforms when the need arises.


I agree with this, though I still use iTerm over Alacritty simply because iTerm’s font rendering is better (in my opinion).


fd-find is great replacement for find. And tokei is a good tool for some basic stats about your codebase.


Knew I was forgetting a big one. fd is so dang handy.

Some others: dust (like du), procs (like ps), zoxide (z), and sd (like sed)


I was pleasantly surprised with bat, I expected it to be overkill but it has made its way into being aliased to cat.

Only qualm would be line number color contrast being mostly terrible, but I don't really need it as much.

What would be kind of interesting is if it would read vim colorschemes, so your cat output is syntax highlighted like if you were editing it.


All these tools are fantastic, though I greatly prefer kitty to alacritty.


Care to elaborate on your preference?


I haven't used Alacritty as much, but Kitty is faster, easier to configure and very convenient in its splits. I believe there's also some problem that Alacritty has with fonts that Kitty doesn't, but I don't remember exactly what.


bat is the first thing a brew install on a fresh Macbook setup. Been using it for years with no idea it's written in Rust.


don't forget to add to your list all the new documentation you'll be reading!


One beauty of rg, sd, fd, etc is that they work almost exactly like their counterparts except they have better default behavior


> supports the DNS-over-TLS and DNS-over-HTTPS protocols, and can emit JSON

This shows how much our old-school Unix tools need an update.

What if all the CLI tools had an option for JSON output and the shell natively supported a query language like `jq`. Then you could pipe commands together:

    host -t A example.org --json-out | ping -c1 --json-in .arecords[0] --json-out | echo --json-in .[0].time > outputfile
This assumes the default output would still be the legacy text format. But if the default output changed to JSON then you could get rid of the ugly json-in/out syntax.


I think a better way to handle your approach would be to attempt to make it automatic; for example, if a program could detect its output as "not a TTY" and then (somehow) make an intelligent determination about what kind of object to pass (i.e. if there was a way for the program on the other end of the pipe to say "Send me object data if you want!") then it would be useful, coupled with programs or commandlets to do filtering.

Having to manually specify "you, output JSON! And you, input JSON! and also filter based on this difficult to remember for most people syntax!" would be cumbersome; much easier to have "commandlets" built into the shell to handle this sort of thing in a sort of composable pipeline. For example:

    host -t A example.org
        | select arecords --limit 1
        | ping -c1
        | select pings.time --limit 1
        | write --append outputfile
As others have said, Powershell supports this, and it's completely awesome to work with. The fact that (assuming proper metadata on the binaries) I can do queries like this is awesome:

    ~ > Get-Command java -All | Sort-Object Version -Descending
    
    CommandType     Name        Version    Source
    -----------     ----        -------    ------
    Application     java.exe    15.0.1.0   C:\Program Files\Java\jdk-15.0.1\bin\java.exe
    Application     java.exe    11.0.6.0   C:\Program Files\Java\jdk-11.0.6\bin\java.exe
    Application     java.exe    8.0.2610.… C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe
This lets you, for example, have multiple versions of something installed, and have a script easily and cleanly get a list of all of them and either choose which one to use, or run something on each (e.g. for testing scripts).

There are also a lot of "that's weird but handy" features, like being able to interact with environment variables the same way you do local files:

    if (Test-Path 'env:GIT_COMMIT') {
        echo "GIT_COMMIT is $Env:GIT_COMMIT"
        $commit_hash = $Env:GIT_COMMIT
    }
Extremely impressed with Microsoft on this implementation. Also worth noting: you can install Powershell on your Linux or macOS systems and use it there as well. Semi-tempted to try implementing things in Powershell as the only cross-platform shell available.


Like probably dozens of others, I've been idly dreaming about reimplementing coreutils / textutils etc to be able to emit and consume structured records in some serialization format.

The thing that would make this really useful is a(t least one) global database of serialization formats to be a lingua franca between tools. Designing those formats to be useful cross-platform would be tough, but you could start with a format db that only promises linux compat, and later add bsd, and maybe windows even later.

edit: google had something like this internally, the "protodb", a versioned repository of protobuf definitions so that any other tool could consume your tool's output.


Some shells, such as elvish [0], nushell [1], mash [2], and even Windows' powershell do support natively manipulating structured data. There is quite a gap between the shell supporting it and tools supporting it, though, and it's a bit of a chicken-and-egg problem.

[0] https://elv.sh/

[1] https://www.nushell.sh/

[2] http://mash-shell.org/


I find jc useful for exactly this purpose -- https://github.com/kellyjonbrazil/jc


Thanks for mentioning this, looks super useful as a bridge.


This is absolutely violation of the unix spirit!

Don't you know that the output of every tool and the format of every configuration file must have their own unique format?

Not even systemd is allowed to use JSON for config files.

/s


Go try powershell for a bit the UX leap forward in treating everything as an object is immense.


As far as I know, freebsd uses libxo, which allows you to use "--libxo" to choose your output format. I hope linux distros will follow that.


dnslookup has been around for a while, and supports DNSCrypt and DNS-over-QUIC (maybe Anonymized DNS, too?) in addition to plain DNS and DoH.

https://github.com/ameshkov/dnslookup


Written in Go, not available in Homebrew (dog is).

I suppose these two could mention each other.


I don't think the Rust version is even close to what github.com/miekg/dns offers.


I actually agree: the thing that library has that dog doesn't is that it's been battle-tested. For example, I've already had to fix a case where it was mis-parsing TXT records because I missed part of the relevant RFC!


The See also list really stumped me, but then I figured it out, it's clever.


This is nice. Is there a shortcut for showing _all_ the record types so I don't have to type out NS, AA, MX etc.?


Ooooh they could have named it Dug. Then you'd have DigDug. On the other hand, this isn't really dig-but-in-rust, so I suppose there is no real reason to relate it.

It does look neat when comparing it to the classic output you have in some other tools; not always the easiest to spot the records in then a lot of debug information that looks the same as 'output' information is often stacked on top of each other making it less readable and even without the colouring this looks like a better fit if you simply want to look at some records.


Ns lookups do not work or kind of look strange?

dig github.com ns

  ; <<>> DiG 9.16.8 <<>> github.com ns
  ;; global options: +cmd
  ;; Got answer:
  ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8592
  ;; flags: qr rd ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 1
  
  ;; OPT PSEUDOSECTION:
  ; EDNS: version: 0, flags:; udp: 1232
  ;; QUESTION SECTION:
  ;github.com.   IN NS
  
  ;; ANSWER SECTION:
  github.com.  46 IN NS dns1.p08.nsone.net.
  github.com.  46 IN NS dns2.p08.nsone.net.
  github.com.  46 IN NS dns3.p08.nsone.net.
  github.com.  46 IN NS dns4.p08.nsone.net.
  github.com.  46 IN NS ns-1283.awsdns-32.org.
  github.com.  46 IN NS ns-1707.awsdns-21.co.uk.
  github.com.  46 IN NS ns-421.awsdns-52.com.
  github.com.  46 IN NS ns-520.awsdns-01.net.

dog github.com ns

   Status: NXDomain
   A github.com.       31s   140.82.121.3
   SOA             23h58m44s A "a.root-servers.net." "nstld.verisign-grs.com." 2020110900 30m00s 15m00s 7d0h00m00s 1d0h00m00s


Ah, different to dig the dns record types _MUST_ be uppercased


The should ignore case or have an error on unknown names. Record types just map to integers.


It's actually doing a lookup for the domain `ns`.

  dog example.com example.net AAAA A
  AAAA example.com. 1d0h00m00s 2606:2800:220:1:248:1893:25c8:1946
     A example.com. 1d0h00m00s   93.184.216.34
  AAAA example.net.  23h45m04s   2606:2800:220:1:248:1893:25c8:1946
     A example.net.  23h45m04s   93.184.216.34


Yeah, it didn't occur to me to not capitalise them, but I've seen many people stumble over this. I'll change it for the next version.


OK, you made me laugh:

See also: mutt, tail, sleep, roff


They forgot biff(1)!


With the existing named dig I'm surprised he didn't choose dug.


Is there support for reverse lookup that I'm just overlooking? There's of PTR records being used for reverse lookups, but no sign of how to do it without reversing the octets by hand.


I didn't think that feature fit. Would people really use a general DNS client for this? I use nslookup.


It already works in dog, so just a matter of adding an option to alleviate the manual work:

  $ dig +short -x 209.216.230.240
  news.ycombinator.com.
  $ dog PTR 240.230.216.209.in-addr.arpa.
  PTR 240.230.216.209.in-addr.arpa. 23h59m44s   "news.ycombinator.com."
And yes, I use dig -x quite often.


Does it need to be an option ? I'm accustomed to using host and it just does it by default if it is given an IP as argument.


This is my thinking too. I could add the option if there's enough interest, but aren't there already dedicated tools to do this?

As an example: I sometimes run 'curl ifconfig.me' to get my public IP from the command-line, but I wouldn't expect curl to add an '--ip' option to make this specific query easier to run. curl is a general tool, and the fact that you can use HTTP to get your public IP doesn't mean it needs a top-level option in an HTTP client. (I get that reverse lookup is an internet standard, and ifconfig.me is a third-party service, but still.)


I don't think gp is against the feature. They're saying

  dog 209.216.230.240
should directly perform a PTR lookup instead of requiring something like

  dog -x 209.216.230.240
Here's how host works when you give it an IP address as opposed to a domain name:

  $ host 209.216.230.240
  240.230.216.209.in-addr.arpa domain name pointer news.ycombinator.com.
  $ host news.ycombinator.com
  news.ycombinator.com has address 209.216.230.240


In my work I use dig -x extensively, and would love to see a similar feature in dog.

If it can see that an argument is an IP address and automatically do the PTR lookup for me, even better!


dig has got the `-x` switch that simplifies the reverse lookups.


I would +1 that I use dig for this all the time.


I really like the Rust implemented tools like ripgrep, bat, exa, fd, lsd etc.

I just tried `cargo build --release --verbose --target x86_64-unknown-linux-musl` with Dog but it uses the `native-tls` Crate that wraps OpenSSL.

It would be great for tools like this to leverage Rustls [0] so one could compile without requiring OpenSSL and be able to compile statically with musl

0. https://github.com/ctz/rustls


Does this client take into account the search domain configured in /etc/resolv.conf ?


It does not — it didn't make the cut for v0.1, but I've raised an issue (#4) so I don't forget about it.


Awesome, dig was long due for a sane replacement. It's output and commandline syntax are about the most obtuse of any mainstream unix CLI tool; it even beats ifconfig and find, which is quite the achievement.


Any reason for not providing binaries?


There are binaries, at least, for three targets: https://github.com/ogham/dog/releases


Got it, thanks! Was thrown off by the README which says "Installing dog requires building it from source."


Ah! My bad, I've simply forgotten to update the README. I'll do it later once I'm done with work.


Additionally, the author maintains the binary AUR for Arch Linux: https://aur.archlinux.org/packages/dog-dns-bin/


Love the name!


The dig like tool on FreeBSD is called drill which is also a nice name I'm my opinion.


Adorable. I hope all command-line tools will add support for emitting well-structured data as JSON soon.


dig does have a YAML option at least


Good to know. But the output seems strange when combinded with '+short'.


[flagged]


This may be snarky, but I really enjoyed reading this as a outrageously subtle commentary on the proliferation of software tooling rewrites.

Gotta say, JSON export alone makes a whole lot of difference with this one though.


This is actually quite amusing




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: