fix querying glue directly

This commit is contained in:
bert hubert
2018-04-10 00:05:41 +02:00
parent 12855f1661
commit 56471fa3f4
4 changed files with 88 additions and 26 deletions

58
tdns/README.md Normal file
View File

@ -0,0 +1,58 @@
# teaching DNS
Welcome to tdns, the teaching authoritative server, implementing all of
basic DNS in 1000 lines of code.
The goals of tdns are:
* Protocol correctness
* Suitable for educational purposes
* Display best practices
Non-goals are:
* Performance
* Implementing more features
# Current status
Features are complete:
* A, AAAA, NS, MX, CNAME, TXT, SOA
* UDP & TCP
* AXFR
* Wildcards
* Delegations
* Glue records
Missing:
* Truncation
* Compression (may not fit in the 1000 lines!)
* EDNS (not 'basic' DNS by our definition, but ok)
Known broken:
* 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
The code is not yet in a teachable state, and the layout is somewhat
confusing: some stuff is in the wrong files.
# Layout
Key to a good DNS implementation is having a faithful DNS storage model.
Over the decades, many many nameservers have started out with an incorrect
storage model, leading to pain later on with empty non-terminals, setting
the 'AA' bit on glue (or not) and eventually DNSSEC ordering problems.
When storing DNS as a tree, as described in RFC 1034, a lot of things go
right "automatically".
The core or `tdns` therefore is the tree of nodes as intended in 1034. This
is implemented in `dns-storage.cc` and `dns-storage.hh`.
This lookup mechanism will tell you if a name is fully present in a zone, or
if it was matched by an NS record. It will also perform wildcard matching,
but not CNAME chasing.
# Best practices
The code does not do any form of DNS escaping. Instead, DNS names are stored
and manipulated as a sequence of DNS labels. So instead of messing with
"www.powerdns.org", we use {"www", "powerdns", "org"}.

View File

@ -18,11 +18,15 @@ bool dnsname::makeRelative(const dnsname& root)
return true;
}
const DNSNode* DNSNode::find(dnsname& name, dnsname& last, bool* passedZonecut) const
const DNSNode* DNSNode::find(dnsname& name, dnsname& last, const DNSNode** passedZonecut, dnsname* zonecutname) const
{
cout<<"find for '"<<name<<"', last is now '"<<last<<"'"<<endl;
if(!last.empty() && passedZonecut && rrsets.count(DNSType::NS)) {
*passedZonecut=true;
if(!last.empty() && rrsets.count(DNSType::NS)) {
cout<<" passed a zonecut, making note of this"<<endl;
if(passedZonecut)
*passedZonecut=this;
if(zonecutname)
*zonecutname=last;
}
if(name.empty()) {
@ -55,7 +59,7 @@ const DNSNode* DNSNode::find(dnsname& name, dnsname& last, bool* passedZonecut)
cout<<" Had match, continuing to child '"<<iter->first<<"'"<<endl;
last.push_front(name.back());
name.pop_back();
return iter->second.find(name, last, passedZonecut);
return iter->second.find(name, last, passedZonecut, zonecutname);
}
DNSNode* DNSNode::add(dnsname name)

View File

@ -81,7 +81,7 @@ struct DNSLabelCompare: public std::binary_function<std::string, std::string, bo
struct DNSNode
{
const DNSNode* find(dnsname& name, dnsname& last, bool* passedZonecut=0) const;
const DNSNode* find(dnsname& name, dnsname& last, const DNSNode** passedZonecut=0, dnsname* zonecutname=0) const;
DNSNode* add(dnsname name);
std::map<dnslabel, DNSNode, DNSLabelCompare> children;
std::map<DNSType, RRSet > rrsets;

View File

@ -76,43 +76,42 @@ try
response.dh.aa = 1;
auto bestzone = fnd->zone;
dnsname searchname(name), lastnode;
bool passedZonecut=false;
dnsname searchname(name), lastnode, zonecutname;
const DNSNode* passedZonecut=0;
int CNAMELoopCount = 0;
loopCNAME:;
passedZonecut=false;
lastnode.clear();
auto node = bestzone->find(searchname, lastnode, &passedZonecut);
if(passedZonecut)
response.dh.aa = false;
loopCNAME:;
lastnode.clear();
zonecutname.clear();
auto node = bestzone->find(searchname, lastnode, &passedZonecut, &zonecutname);
if(!node) {
cout<<"Found nothing in zone '"<<zone<<"' for lhs '"<<name<<"'"<<endl;
}
else if(!searchname.empty()) {
cout<<"This was a partial match, searchname now "<<searchname<<endl;
else if(passedZonecut) {
response.dh.aa = false;
cout<<"This is a delegation, zonecutname: '"<<zonecutname<<"'"<<endl;
for(const auto& rr: node->rrsets) {
for(const auto& rr: passedZonecut->rrsets) {
cout<<" Have type "<<rr.first<<endl;
}
auto iter = node->rrsets.find(DNSType::NS);
if(iter != node->rrsets.end() && passedZonecut) {
cout<<"Have delegation"<<endl;
auto iter = passedZonecut->rrsets.find(DNSType::NS);
if(iter != passedZonecut->rrsets.end()) {
const auto& rrset = iter->second;
vector<dnsname> toresolve;
for(const auto& rr : rrset.contents) {
response.putRR(DNSSection::Authority, lastnode+zone, DNSType::NS, rrset.ttl, rr);
response.putRR(DNSSection::Authority, zonecutname+zone, DNSType::NS, rrset.ttl, rr);
toresolve.push_back(dynamic_cast<NameGenerator*>(rr.get())->d_name);
}
addAdditional(bestzone, zone, toresolve, response);
}
else {
cout<<"This is an NXDOMAIN situation"<<endl;
const auto& rrset = fnd->zone->rrsets[DNSType::SOA];
response.dh.rcode = (int)RCode::Nxdomain;
response.putRR(DNSSection::Authority, zone, DNSType::SOA, rrset.ttl, rrset.contents[0]);
}
}
else if(!searchname.empty()) {
cout<<"This is an NXDOMAIN situation"<<endl;
const auto& rrset = fnd->zone->rrsets[DNSType::SOA];
response.dh.rcode = (int)RCode::Nxdomain;
response.putRR(DNSSection::Authority, zone, DNSType::SOA, rrset.ttl, rrset.contents[0]);
}
else {
cout<<"Found something in zone '"<<zone<<"' for lhs '"<<name<<"', searchname now '"<<searchname<<"', lastnode '"<<lastnode<<"', passedZonecut="<<passedZonecut<<endl;
@ -338,6 +337,7 @@ void loadZones(DNSNode& zones)
newzone->add({"ns1", "fra"})->rrsets[DNSType::A].add(AGenerator::make("12.13.14.15"));
newzone->add({"NS2", "fra"})->rrsets[DNSType::A].add(AGenerator::make("12.13.14.16"));
newzone->add({"NS2", "fra"})->rrsets[DNSType::AAAA].add(AAAAGenerator::make("::1"));
}
int main(int argc, char** argv)