I know it starts like a shallow dismissal, but mentioning that code uses another DNS package as a dependency (miekg/dns) has a point. I originally missed that, and I believe many probably too.
I don't think author can claim "in 80 lines of code" when the code depends on a much bigger library than itself.
The original title was "Writing a DNS resolver in 80 lines of Go".
The comment might seem like its being dismissive with the current title "A toy DNS resolver", but at the time of writing it was not just a shallow dismissal.
This is a surpassingly facile putdown. `miekg/dns` is being used here as a DNS request/response parser library. There's almost nothing interesting about parsing DNS messages. The interesting logic in the DNS is the recursive lookup, which is the part this post captures.
As far as I know (we use the same library for our authority servers) `miekg/dns` doesn't even do recursive lookups.
It's not just that, though. It's also that recursive lookups are the probably the most mystifying aspect of DNS. DNS message parsers are straight-line code; there are lots of them, including in POSIX libc. What you don't have in POSIX libc is a function that does a complete from-the-root recursive lookup for a name; most DNS "client" implementations stop at "send the request to the local recursive cache".
To see that function implemented in such a tiny amount of code is itself super interesting.
Essentially, what you're saying is that the article disappointed you because it purported to be about making pizza, but didn't first specify how to make the oven.
I disagree. The entire client connection is being handled by the imported DNS library:
func dnsQuery(name string, server net.IP) *dns.Msg {
fmt.Printf("dig -r @%s %s\n", server.String(), name)
msg := new(dns.Msg)
msg.SetQuestion(name, dns.TypeA)
c := new(dns.Client)
reply, _, _ := c.Exchange(msg, server.String()+":53")
return reply
}
func main() {
name := os.Args[1]
if !strings.HasSuffix(name, ".") {
name = name + "."
}
fmt.Println("Result:", resolve(name))
}
While I agree it's impressively simply laid out and as an exercise good to see people getting hands-on with underpinning protocols (I'm a fan of this), it also does its job as a follow up to her previous blog post on the subject.
People taking umbrage with the title as posted here (and the original site title) are IMO not wrong. The article title has been changed to "A toy DNS resolver" now, so obviously it was contentious enough that she thought to change it.
What do you think an "entire client connection" is? It's a read and a write from a net.Conn. Read client.go's (c *Client) exchange() (the lowercase one). It's 30 lines of code, and that includes stuff like EDNS0, TSIG, and read deadlines that have nothing to do with the functionality the author is demonstrating.
If the author took the time to write a 15 line roundTrip() function that called m.Pack(), udpConn.Write(), udpConn.SetDeadline(1s), and udpConn.Read(), would your argument here evaporate? Then it's not a very good argument, is it?
>Essentially, what you're saying is that the article disappointed you because it purported to be about making pizza, but didn't first specify how to make the oven.
No it's more akin about him saying he made a pizza, but all that was done was import a pizza and then sprinkle some pepperoni on it.
Imagine if I said I made an HTTP server in 6 lines.
I think it would be reasonable for people to say that I didn't make a HTTP server in 6 lines.
Just how I used a library to make a HTTP server me and I handled requests/responses, the author of this article used a library to handle DNS requests/responses. The 80 lines figure for making a DNS resolver is misleading when there are 26k lines of Go code (according to cloc) for handling DNS that are just in a library instead of the main file.
You have managed simultaneously to radically underestimate the complexity of Node and Express's HTTP handling, while at the same time radically overestimating the complexity of what miekg/dns is being asked to do here.
The majority of the 20,000 lines of non-test code in miekg/dns are just handlers for record types the author of this article didn't need; much of the rest of it is stuff like zone file parsing and DNSSEC signatures, which again have nothing to do with what the author wrote.
What you conspicuously won't find in miekg/dns: a recursive lookup routine.
>What you conspicuously won't find in miekg/dns: a recursive lookup routine.
Sure, but it implements the building blocks that you need to create one. Those building blocks are going to be where a good chunk of code is going to be. (Yes, there is a lot of code from that library that will be unused)
More than a little unfair when the following is in the article:
I’m not going to write this completely from
scratch – I think parsing DNS packets is really
interesting, but it’s definitely more than 80
lines of code, and I find that it kind of
distracts from the algorithm.
Which, seems legit to me. This article was a fun read to refresh on exactly what goes on in resolving basic records.
I hereby do fully deny that there is anything the least bit clickbait-ish about this article, which is super interesting and all the more an achievement for its brevity. It demystifies what is the most annoying thing about trying to code the client side of DNS, and the fact that it uses the same DNS message parsing library every other Go programmer does isn't of the slightest import --- if the article hadn't used miekg/dns, some other lowbrow comment would be taking the author to task for reinventing the message codec wheel.
The world needs more simple recursive lookup examples, and absolutely does not need more explication of DNS message parsing, any more than than an article talking about etcd's Raft implementation would benefit from a hand-rolled implementation of Protobufs.
It's (sadly) telling that all the dismissals are focused on packet parsing, and not like, bailiwick checking, which is understandably missing, but also really important.
This is the key case I wish HN allowed editorializing the title. Regardless how good the article is (or isn't) when they have titles like this it's inevitable the conversation will be about how the title was overreaching. If people were encouraged to make titles like this into something like "Making a simple DNS resolver with miekg/dns in Go" or even just "A DNS resolver in Go" when posting we'd avoid this multiple times a day recurring problem.
Or maybe it already is encouraged and people just aren't aware this counts as "misleading" or "linkbait" since it's not well described what the cutoff point is.
Either way both titles like this one and discussions of have long gotten old.
Edit: looks like the article moved to "A toy DNS resolver", excellent choice of wording IMO.
"Making a simple DNS resolver with miekg/dns in Go" would have given me the false impression that the article was about how to use miekg/dns. "A DNS resolver in Go" would have given me the false impression that it was about a full-fledged DNS resolver meant for integrating with Go applications. The current title at least pushed me in the direction of understanding what the article is about, which is demonstrating how DNS resolution works using a short Go program.
That wouldn't be a false impression, this article is indeed about how to use miekg/dns to make a resolver. Your comments on the other title already apply to the current title as is, it's one of things people hate about these titles but at least the cut title avoids the line count/"nothing is from scratch" debates.
Increasingly more accurate titles always accepted of course though but one thing for sure is the class of "<x> in <y lines>" are demonstrably a continuous problem to the point they are talked about instead of the articles they represent, they are not just minor wording nits one could come up with after staring at a title long enough.
Edit: I really like the title the article itself changed to "A toy DNS resolver".
A small nit but it's actually important for the HN Rules of Titles: 'edit' and 'editorialize' are different things. You can sometimes edit a title, for instance if it's misleading or clickbait. You can't editorialize in titles no matter what.
The more general take I have seen is that it would give a "priority comment". That can result in problems like that but also more commonly just cause the comments to all act like a response to the "main" comment rather than general discourse on the topic. I can definitely see that though I also see the poster having a large amount of that control already in most cases since they get to pick the source they post.
I smiled at this, though the Sagan quote "If you wish to make an apple pie from scratch, you must first invent the universe" springs to mind. At some point to be reasonable you have to cut off the lower layers of abstraction or else it's madness.
Unbound leans on libresolv, so I don't think it's cheating to lean on external libraries - most of the hard part about resolvers is all the crufty RFCs you have to support anyway, not the basic nuts and bolts of resolving an A record.
I normally don't like comments like this but I think in this case your point stands. DNS is not 'easy' in that you have troves of RFCs and undocumented but expected behaviors to follow, etc. miekg/dns does all of the heavy lifting here.
Writing a resolver in it is a fun project, but bragging about the line count is silly.
miekg/dns literally only handles building/parsing the dns packets. Which may be a complicated activity and perhaps for you equals "doing all the heavy lifting" But it is absolutely not doing the "recursive resolve" algorithm at all here. I think parsing network packets is interesting but it's not the point of the article and saying that miekg/dns is doing all the heavy lifting doesn't give the article or it's author enough credit.
Honestly the comments of this type on this article sound more like you didn't actually read the article and are just knee jerk putting someone down. I hope that is not the case but maybe it would be good to examine why the message is coming off so distastefully.
miekg/dns is doing almost none of the heavy lifting here, which you can verify for yourself by counting the number of record types this code actually needs to parse to function, and comparing it to the number of record types miekg/dns supports and how much of the code exists just to dispatch to random record type handlers.
Correct; none of that is the heavy lifting of a recursive lookup. One way you know that is that similar code lives in every libc, but no libc I know of has a recursive resolver; the pattern of fobbing off complicated recursive queries to cache servers is so common that there's a name for library-style resolvers: "stub resolver".
You're not going to win this argument, no matter how many synonyms for "encode" and "decode" you come up with.
You have one extra "your" the final clause of that last sentence.
I'm not messing with you; as someone who does an unfortunate amount of DNS hacking, it is crazymaking to see so many people express the opinion that the hard part of doing DNS is just formatting the records. The argument you're presenting is a little like saying that "malloc" would be doing the heavy lifting in a C implementation of a graph minimum cost spanning tree.
This also isn't just an aesthetic argument. There is something profound about it. No language standard library I'm aware of includes a recursive lookup, despite the fact that you've pegged it as a "12 line for loop". They all in some way or other include DNS message codecs, but not the recursive lookup, despite the fact that it would be immensely useful to be able to write programs that did recursive lookups directly rather than relying on the system's configured recursive resolver. The reason for that is at least partly that recursive lookup is mystifying and spooks library implementors.
I've had the displeasure of writing both a series of DNS codecs and a recursive lookup routine. The codecs I've done throughout my career, going back to like 1997 with exploits for the Kashpureff cache poisoning bug. The recursor I finally got around to writing just a couple months ago, because recursive lookups are freaking complicated.
That the author got this recursive lookup so small that it broke everyone's brains is just more reason to be interested in this article. It's certainly not a reason to dismiss it. The reactions on this thread are pretty embarrassing.
Cannot second this enough. miekg/dns is probably tens of thousands of mature lines
of code covering all aspects of the DNS protocol. This feels like bragging about creating an minimal http client but really you just used libcurl to do the heavy lifting.
It is nothing at all like using libcurl to do an HTTP request, as libcurl handles the semantics of the HTTP protocol, and not just marshaling and unmarshaling HTTP requests and responses.
miekg/dns is also 20,000 lines of code most of which are not relevant to the task of doing a recursive lookup.
Seems more like writing an article where you explain how HTTP caching headers work by using libcurl to write a program to mirror a website. The purpose isn't showing off, it's education.
https://news.ycombinator.com/newsguidelines.html