/* Goal: a fully standards compliant basic authoritative server. In <1000 lines. Non-goals: notifications, slaving zones, name compression, edns, performance */ #include #include #include #include #include "sclasses.hh" #include "dns.hh" #include "safearray.hh" #include #include #include "dns-types.hh" #include "dns-storage.hh" using namespace std; void addAdditional(const DNSNode* bestzone, const dnsname& zone, const vector& toresolve, DNSMessageWriter& response) { for(auto addname : toresolve ) { cout<<"Doing additional or glue lookup for "<find(addname, wuh); if(!addnode || !addname.empty()) { cout<<" Found nothing, continuing"<rrsets.find(type); if(iter2 != addnode->rrsets.end()) { const auto& rrset = iter2->second; for(const auto& rr : rrset.contents) { response.putRR(DNSSection::Additional, wuh+zone, type, rrset.ttl, rr); } } } } } bool processQuestion(const DNSNode& zones, DNSMessageReader& dm, const ComboAddress& local, const ComboAddress& remote, DNSMessageWriter& response) try { dnsname name; DNSType type; dm.getQuestion(name, type); cout<<"Received a query from "<zone) { cout<<"---\nBest zone: "<zone<zone; dnsname searchname(name), lastnode, zonecutname; const DNSNode* passedZonecut=0; int CNAMELoopCount = 0; loopCNAME:; lastnode.clear(); zonecutname.clear(); auto node = bestzone->find(searchname, lastnode, &passedZonecut, &zonecutname); if(!node) { cout<<"Found nothing in zone '"<rrsets) { cout<<" Have type "<rrsets.find(DNSType::NS); if(iter != passedZonecut->rrsets.end()) { const auto& rrset = iter->second; vector toresolve; for(const auto& rr : rrset.contents) { response.putRR(DNSSection::Authority, zonecutname+zone, DNSType::NS, rrset.ttl, rr); toresolve.push_back(dynamic_cast(rr.get())->d_name); } addAdditional(bestzone, zone, toresolve, response); } } else if(!searchname.empty()) { cout<<"This is an NXDOMAIN situation"<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 '"<second; dnsname target; for(const auto& rr : rrset.contents) { response.putRR(DNSSection::Answer, lastnode+zone, DNSType::CNAME, rrset.ttl, rr); target=dynamic_cast(rr.get())->d_name; } if(target.makeRelative(zone)) { cout<<" Should follow CNAME to "<zone->rrsets[DNSType::SOA]; response.putRR(DNSSection::Answer, zone, DNSType::SOA, rrset.ttl, rrset.contents[0]); } addAdditional(bestzone, zone, additional, response); } } else { cout<<"No zone matched"< 512) { cerr<<"Remote "<find(name, zone); if(!fnd || !fnd->zone || !name.empty() || !fnd->zone->rrsets.count(DNSType::SOA)) { cout<<" This was not a zone, or zone had no SOA"<zone; // send SOA response.putRR(DNSSection::Answer, zone, DNSType::SOA, node->rrsets[DNSType::SOA].ttl, node->rrsets[DNSType::SOA].contents[0]); writeTCPResponse(sock, response); response.setQuestion(zone, type); // send all other records node->visit([&response,&sock,&name,&type,&zone](const dnsname& nname, const DNSNode* n) { for(const auto& p : n->rrsets) { if(p.first == DNSType::SOA) continue; for(const auto& rr : p.second.contents) { retry: try { response.putRR(DNSSection::Answer, nname, p.first, p.second.ttl, rr); } catch(...) { // exceeded packet size writeTCPResponse(sock, response); response.setQuestion(zone, type); goto retry; } } } }, zone); writeTCPResponse(sock, response); response.setQuestion(zone, type); // send SOA again response.putRR(DNSSection::Answer, zone, DNSType::SOA, node->rrsets[DNSType::SOA].ttl, node->rrsets[DNSType::SOA].contents[0]); writeTCPResponse(sock, response); return; } else { dm.payload.rewind(); if(processQuestion(*zones, dm, local, remote, response)) { writeTCPResponse(sock, response); } else return; } } } int main(int argc, char** argv) try { if(argc != 2) { cerr<<"Syntax: tdns ipaddress:port"<