What is this?
A toy DNS for hobbyists and worried people.
Mission Statement:
Features:
- Really easy to configure (toml syntax)
- Rule engine to rewrite/deny queries
- Plugins support
But also:
- RFC2136 and LetsEncrypt compatibility, use as a DNS endpoint to obtain certificates
- Configuration auto-update
Configuration, Documentation
Take a look at the content of the config.toml.template
file. Copy it to config.toml
and run.
Read the CONCISE DOCUMENTATION 📖
DNS Synchronization
There is currently no notion of primary and secondary DNS. All your DNS instances are equal. It would be fairly easy to implement IXFR/AXFR
but unless it becomes a mandatory feature, this seems to go against my "no fat/easy to configure" goals. With this being said, you could use something like Syncthing to keep config.toml
current.
Tell me more about the DNS repository
In the github.com/miekg/dns
repository, there was a pull request allowing code using that library to retrieve additional information about the requesting socket. This includes source IP, which can be convenient in a split horizon environment. It lives in this directory (slightly adapted)
The tests below are performed using authoritative (local) records as my main goal is to offer a server that can survive a brutal assault serving cloud endpoints. Performing the same test against recursed hosts offers similar performance, simply because I am not querying 1M different hosts and the server efficiently*
caches responses (while respecting their TTL)
These tests are run locally on a 2020 Macbook M1 Pro and jMeter is using as much CPU as it dares to, while kittendns doesn't even appear in my top output.
*
dumbly
jMeter stress testing
- Run Wireshark to capture a DNS query. In the details window, select the Domain Name System layer, right-click, copy as a hex stream.
- In jMeter, paste in the "Request Data" area
The jMeter test plan is stored in KittenDNS jMeter Test Plan.jmx
Since we are testing DDoS-type scenarios, we are not going to allow any ramp-up. All clients will be hitting the servers from the beginning.
Results:
Scenario |
Queries/Minute |
Queries/Second |
1M queued queries for locally resolved hosts |
1.3M |
21,666 |
1M queued queries for locally resolved, CNAME'd hosts |
1.276M |
21,417 |
1M queries, but by 100 users, no ramp-up |
4.599M |
76,650 |
1M queries, 100 users, flattening enabled |
4.623M |
77,050 |
1M queries, bump to 1,000 users |
3.2M |
53,333 |
Observations:
- If we distribute across 1000 users rather than 100, threading starts degrading.
- Flattening doesn't provide the expected level of improvement.
Latency is pretty good, too.
Mig testing
https://github.com/infobloxopen/dnstools/tree/master/mig
./mig -s 192.168.1.189 -n 1000000 -d domains.lst -o perf.json
python2 ../analyser/fit.py results/perf.json
Results:
Rule Engine |
Queries/Minute |
Queries/Second |
Enabled |
6.7M |
111,677 |
Disabled |
6.79M |
113,181 |
Again, a somewhat unexpected result: a lightly loaded rule engine has almost no impact on the server's performance.
Todo
Cache improvements
- If flattening is enabled, we should cache the flattened version.
- When flattening, what about recursed and fragmented answers?
Circuit Breaker (when recursing)/Rate Limiter
Because, realistically, it is better to fail some queries if this will allow them to succeed later.
Rate Limiter: should be limiting some misbehaving clients. Problem: how do we identify a "Client?"
- Is a client a single IP address? If it's a site DNS proxying to us, then it may be allowed higher traffic levels
- Should we throttle a combination of source + queries?
FAQ
Q: I noticed that you are storing similar records in separate structures. For instance, there is one entry for a A (v4) record,
and another entry for its AAAA (v6) counterpart. This is wasteful!
A: You are correct. However, I should not store both entries using the same key because they can both be capitalized differently.
And, little known fact, capitalization in DNS can be a security feature.
Q: What's that about capitalization?
A: KittenDNS makes sure that the response to a query returns the host capitalized exactly as it was in the query.
This is a protection scheme against DNS poisoning, known as the '0x20' trick.
Misc