4 ms·
A guide to writing a DNS Server from scratch in Rust
- robgolding 6y agoThis 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.
- dnautics 6y agoDo you have a link to your toy dns proxy?
- SoylentBob 6y agoHaving multiple TTLs in the same record set is deprecated. [1] If you would rather put them in your cache, instead of not allowing to request them through your server, you are probably best off, by taking the lower TTL and using that as your initial TTL. E.g. this is how an authoritative Knot instance would handle differing TTLs in a DNSSEC signed zone. [1] https://tools.ietf.org/html/rfc2181#section-5.2 https://tools.ietf.org/html/rfc2181#section-5.2
- zokier 6y agoI 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 6y agoFrom 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 6y agoIs there a similar guide out there for Go? Would be great to compare.
- macdj 6y agoI 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 6y agoI'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 6y agoSometimes 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 6y agoYou are pronoid :) https://en.wikipedia.org/wiki/Pronoia_(psychology) https://en.wikipedia.org/wiki/Pronoia_(psychology)
- oxymoron 6y agoI’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 6y agoThe 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 6y agoYeah, 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 6y agoDNS 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 6y agoTook me a few days before I could get to it, but this has been fixed now.
- Areading314 6y agoWhy would someone need to write their own instead of just running bind?
- bauerd 6y agoLearning how it works
- andris9 6y agoI 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 6y agoVery cool!
- jlgaddis 6y agoWe're geeks and this is HN. "Need" is irrelevant and has nothing to do with it.
- kjs3 6y agoMonocultures are bad, for one. A diversity of implementations drives improvements. For example, at one time one could have said "...instead of just running sendmail?" for SMTP servers. But the emergence of things like exim, qmail and especially postfix resulted in better servers.