From cc9a13b29a383b56e6b8c41999cf971fadefb6b6 Mon Sep 17 00:00:00 2001 From: bert hubert Date: Thu, 12 Apr 2018 00:04:59 +0200 Subject: [PATCH] add EDNS, proper label ordering including embedded zeros, update docs --- tdns/README.md | 8 ++++---- tdns/contents.cc | 4 +++- tdns/dns-storage.hh | 22 ++++++++++++++++------ tdns/dnsmessages.cc | 17 ++++++++++++++++- tdns/dnsmessages.hh | 2 ++ tdns/tdns.cc | 30 ++++++++++++++++++++++++++---- 6 files changed, 67 insertions(+), 16 deletions(-) diff --git a/tdns/README.md b/tdns/README.md index 4a19b9b..d0c719d 100644 --- a/tdns/README.md +++ b/tdns/README.md @@ -26,14 +26,14 @@ Features are complete: * Delegations * Glue records * Truncation + * EDNS (buffer size, no options) Missing: - * Compression (may not fit in the 1000 lines!) - * EDNS (not 'basic' DNS by our definition, but ok) + * Compression (may not fit in the 1200 lines!) Known broken: - * Embedded 0s in DNS labels don't yet work - * Case-insensitive comparison isn't 100% correct + * ~~Embedded 0s in DNS labels don't yet work~~ + * ~~Case-insensitive comparison isn't 100% correct~~ * RCode after one CNAME chase * On output (to screen) we do not escape DNS names correctly * TCP/IP does not follow recommended timeouts diff --git a/tdns/contents.cc b/tdns/contents.cc index 5c50740..beb3407 100644 --- a/tdns/contents.cc +++ b/tdns/contents.cc @@ -28,7 +28,9 @@ void loadZones(DNSNode& zones) newzone->add({"fra"})->addRRs(NSGen::make({"ns1","fra","powerdns","org"}), NSGen::make({"ns1","fra","powerdns","org"})); newzone->add({"ns1"})->addRRs(AGen::make("212.13.14.15")); newzone->add({"ns1", "fra"})->addRRs(AGen::make("12.13.14.15")); - newzone->add({"NS2", "fra"})->addRRs(AGen::make("12.13.14.16"), AAAAGen::make("::1")); + newzone->add({"NS2", "fra"})->addRRs(AGen::make("12.13.14.16")); + newzone->add({"ns2", "fra"})->addRRs(AAAAGen::make("::1")); + newzone->add({"something"})->addRRs(AAAAGen::make("::1"), AGen::make("12.13.14.15")); newzone->add({"time"})->addRRs(ClockTXTGen::make("The time is %a, %d %b %Y %T %z")); } diff --git a/tdns/dns-storage.hh b/tdns/dns-storage.hh index c21ff27..9ca4d2b 100644 --- a/tdns/dns-storage.hh +++ b/tdns/dns-storage.hh @@ -14,18 +14,28 @@ class dnslabel { public: dnslabel() {} - dnslabel(const char* s) : d_s(s) {} // XXX check length here! + dnslabel(const char* s) : dnslabel(std::string(s)) {} dnslabel(const std::string& s) : d_s(s) {} // XXX check length here! bool operator<(const dnslabel& rhs) const { - return strcasecmp(d_s.c_str(), rhs.d_s.c_str()) < 0; // XXX locale pain, plus embedded zeros + return std::lexicographical_compare(d_s.begin(), d_s.end(), rhs.d_s.begin(), rhs.d_s.end(), charcomp); } bool operator==(const dnslabel &rhs) const { - return strcasecmp(d_s.c_str(), rhs.d_s.c_str()) == 0; // XXX locale pain, plus embedded zeros + return !(*this < rhs) && !(rhs<*this); } auto size() const { return d_s.size(); } std::string d_s; +private: + static bool charcomp(char a, char b) + { + if(a >= 0x61 && a <= 0x7A) + a -= 0x20; + if(b >= 0x61 && b <= 0x7A) + b -= 0x20; + return a < b; + } + }; std::ostream & operator<<(std::ostream &os, const dnslabel& d); @@ -40,12 +50,12 @@ SMARTENUMEND(RCode) enum class DNSType : uint16_t { - A = 1, NS = 2, CNAME = 5, SOA=6, PTR=12, MX=15, TXT=16, AAAA = 28, SRV=33, IXFR = 251, AXFR = 252, ANY = 255 + A = 1, NS = 2, CNAME = 5, SOA=6, PTR=12, MX=15, TXT=16, AAAA = 28, SRV=33, OPT=41, IXFR = 251, AXFR = 252, ANY = 255 }; SMARTENUMSTART(DNSType) -SENUM13(DNSType, A, NS, CNAME, SOA, PTR, MX, TXT, AAAA, IXFR, AAAA, SRV, IXFR, AXFR) -SENUM(DNSType, ANY) +SENUM13(DNSType, A, NS, CNAME, SOA, PTR, MX, TXT, AAAA, IXFR, AAAA, SRV, OPT, IXFR) +SENUM2(DNSType, AXFR, ANY) SMARTENUMEND(DNSType) COMBOENUM4(DNSSection, Question, 0, Answer, 1, Authority, 2, Additional, 3) diff --git a/tdns/dnsmessages.cc b/tdns/dnsmessages.cc index f49eeec..216b0c5 100644 --- a/tdns/dnsmessages.cc +++ b/tdns/dnsmessages.cc @@ -22,9 +22,9 @@ void DNSMessageReader::getQuestion(dnsname& name, DNSType& type) { name=getName(); type=(DNSType)payload.getUInt16(); + payload.getUInt16(); // skip the class } - void DNSMessageWriter::putRR(DNSSection section, const dnsname& name, DNSType type, uint32_t ttl, const std::unique_ptr& content) { auto cursize = payloadpos; @@ -55,6 +55,21 @@ void DNSMessageWriter::putRR(DNSSection section, const dnsname& name, DNSType ty } } +void DNSMessageWriter::putEDNS(uint16_t bufsize, bool doBit) +{ + auto cursize = payloadpos; + try { + putUInt8(0); putUInt16((uint16_t)DNSType::OPT); // 'root' name, our type + putUInt16(bufsize); putUInt16(0); putUInt8(doBit ? 0x80 : 0); putUInt8(0); + putUInt16(0); + } + catch(...) { + payloadpos = cursize; + throw; + } + dh.nscount = htons(ntohs(dh.nscount)+1); +} + void DNSMessageWriter::setQuestion(const dnsname& name, DNSType type) { dh.ancount = dh.arcount = dh.nscount = 0; diff --git a/tdns/dnsmessages.hh b/tdns/dnsmessages.hh index aa1cc4e..c84c2fc 100644 --- a/tdns/dnsmessages.hh +++ b/tdns/dnsmessages.hh @@ -25,6 +25,8 @@ struct DNSMessageWriter std::vector payload; void setQuestion(const dnsname& name, DNSType type); void putRR(DNSSection section, const dnsname& name, DNSType type, uint32_t ttl, const std::unique_ptr& rr); + + void putEDNS(uint16_t bufsize, bool doBit); std::string serialize() const; uint16_t payloadpos=0; diff --git a/tdns/tdns.cc b/tdns/tdns.cc index 17bf789..54eb8cd 100644 --- a/tdns/tdns.cc +++ b/tdns/tdns.cc @@ -44,12 +44,28 @@ void addAdditional(const DNSNode* bestzone, const dnsname& zone, const vector sizeof(dnsheader)) + response.payload.resize(newsize - sizeof(dnsheader)); + + } + } try { response.dh = dm.dh; response.dh.ad = response.dh.ra = response.dh.aa = 0; @@ -162,19 +178,25 @@ bool processQuestion(const DNSNode& zones, DNSMessageReader& dm, const ComboAddr response.putRR(DNSSection::Answer, zone, DNSType::SOA, rrset.ttl, rrset.contents[0]); } addAdditional(bestzone, zone, additional, response); - } } else { cout<<"No zone matched"<