
A guide to writing a DNS Server from scratch in Rust - eatonphil
https://github.com/EmilHernvall/dnsguide
======
oxymoron
I’m the author of this. Fun to see it appear here a few years after I wrote
it. I originally put this together in an attempt to fish for a Rust gig. It
worked out! I current coworker of mine saw it in /r/rust and passed my name to
their recruiter.

I’ve felt at times that this project is a bit dated in that it uses
synchronous io. I’ve changed my mind about that though. It’s more about
teaching DNS than about teaching rust, and async is complex enough that it’d
be a pedagogical impedement. Synchronous rust, on the other hand, is very
simple to grasp.

~~~
fanf2
The first thing I check in DNS software is whether there is a trivial denial
of service attack in the name decompression code. Sadly this code fails :-(

It is vital that you have a limit on the number of label pointers that you
follow, either by ensuring the pointer points to an earlier point in the
packet, or by limiting the number of indirections.

~~~
oxymoron
Yeah, it was pointed out by someone on /r/rust when I first posted it. I
thought I had corrected that, but apparently not. I’ll revise that tonight.
It’s obviously a bad mistake.

~~~
fanf2
DNS name (de)compression is _super_ tricky and even experts get it wrong in
production code, so it's a forgivable mistake :-)

It's an interesting trap/pitfall, though, because it's an example of a
situation where basic memory safety isn't enough. I would love to see some
examples of how to use Rust's type system to protect against DNS name
compression loops, e.g. using a slice of the packet to force compression
pointers to go backwards.

~~~
oxymoron
Took me a few days before I could get to it, but this has been fixed now.

------
robgolding
This is a fantastic and well-written guide, thank you!

I recently wrote a toy caching DNS proxy in Elixir, and I have a question
which I’ve never been able to figure out. Individual DNS records for the same
hostname can have different TTLs configured. For example, 30s for one record
and 300s for another. As a caching resolver, what is the expected behaviour
when the record with the shorter TTL has expired but the other has not? I
chose to invalidate the entire thing and make a new query upstream, but I’ve
always wondered what the “proper” behaviour should be.

~~~
zokier
I haven't written a dns server so this might be stupid question, but why would
differing TTLs be a problem? You'd need just to key your cache with (label,
recordtype) tuple, right?

~~~
DougBTX
From the RFC link in a sibling comment[1]:

> No uses for this have been found that cannot be better accomplished in other
> ways. This can, however, cause partial replies (not marked "truncated") from
> a caching server, where the TTLs for some but not all the RRs in the RRSet
> have expired.

So the cache could be split up like that, but then it could produce partial
results, which is worse than reducing the effective TTL.

[1]
[https://tools.ietf.org/html/rfc2181#section-5.2](https://tools.ietf.org/html/rfc2181#section-5.2)

------
haywirez
Is there a similar guide out there for Go? Would be great to compare.

~~~
macdj
I don't know of a guide but there's lots of projects built on miekg's DNS
package: [https://github.com/miekg/dns/](https://github.com/miekg/dns/)

------
macdj
I'd encourage anyone looking to learn more about DNS to check out Bert
Hubert's Hello DNS project at [https://powerdns.org/hello-
dns/](https://powerdns.org/hello-dns/).

------
ashildr
Sometimes it‘s like somebody is reading my brain. I was just considering to
have a look into DNS to solve a particular problem with software-licensing /
enforcement. It‘s still likely a wrong idea and not well thought out, but I‘m
even closer to actually waste resources on it, now :-)

~~~
n_t
You are pronoid :)

[https://en.wikipedia.org/wiki/Pronoia_(psychology)](https://en.wikipedia.org/wiki/Pronoia_\(psychology\))

------
Areading314
Why would someone need to write their own instead of just running bind?

~~~
andris9
I built PendingDNS ([https://github.com/postalsys/pending-
dns](https://github.com/postalsys/pending-dns)) for a service I run mostly for
two reasons:

1) no need to mess with zone files, all data is written to and read from
Redis, so it is much easier to integrate

2) changes are always immediate, no need to reload server daemon, which means
I can generate DNS based Lets Encrypt wildcard certificates really fast as
there is no need to wait for “propagation”

~~~
Areading314
Very cool!

