/* 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 "record-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) { DNSName qname; DNSType qtype; dm.getQuestion(qname, qtype); DNSName origname=qname; // we need this for error reporting, we munch the original name bool haveEDNS=false; cout<<"Received a query from "< sizeof(dnsheader)) response.payload.resize(newsize - sizeof(dnsheader)); try { response.dh = dm.dh; response.dh.ad = response.dh.ra = response.dh.aa = 0; response.dh.qr = 1; response.setQuestion(qname, qtype); if(qtype == DNSType::AXFR || qtype == DNSType::IXFR) { cout<<"Query was for AXFR or IXFR over UDP, can't do that"<zone) { cout<<"No zone matched"<zone; DNSName searchname(qname), lastnode, zonecutname; const DNSNode* passedZonecut=0; int CNAMELoopCount = 0; loopCNAME:; auto node = bestzone->find(searchname, lastnode, &passedZonecut, &zonecutname); if(passedZonecut) { response.dh.aa = false; cout<<"This is a delegation, zonecutname: '"<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+zonename, DNSType::NS, rrset.ttl, rr); toresolve.push_back(dynamic_cast(rr.get())->d_name); } addAdditional(bestzone, zonename, toresolve, response); } } else if(!searchname.empty()) { cout<<"This is an NXDOMAIN situation"<rrsets[DNSType::SOA]; response.putRR(DNSSection::Authority, zonename, DNSType::SOA, rrset.ttl, rrset.contents[0]); } else { cout<<"Found something in zone '"<second; response.putRR(DNSSection::Answer, lastnode+zonename, DNSType::CNAME, rrset.ttl, rrset.contents[0]); DNSName target=dynamic_cast(rrset.contents[0].get())->d_name; if(target.makeRelative(zonename)) { cout<<" Should follow CNAME to "<rrsets.find(qtype), iter != node->rrsets.end() || (!node->rrsets.empty() && qtype==DNSType::ANY)) { auto range = make_pair(iter, iter); if(qtype == DNSType::ANY) range = make_pair(node->rrsets.begin(), node->rrsets.end()); else ++range.second; for(auto i2 = range.first; i2 != range.second; ++i2) { const auto& rrset = i2->second; for(const auto& rr : rrset.contents) { response.putRR(DNSSection::Answer, lastnode+zonename, i2->first, rrset.ttl, rr); if(i2->first == DNSType::MX) additional.push_back(dynamic_cast(rr.get())->d_name); } } } else { cout<<"Node exists, qtype doesn't, NOERROR situation, inserting SOA"<rrsets[DNSType::SOA]; response.putRR(DNSSection::Answer, zonename, DNSType::SOA, rrset.ttl, rrset.contents[0]); } addAdditional(bestzone, zonename, additional, response); } if(haveEDNS) { response.putEDNS(newsize, doBit); } return true; } catch(std::out_of_range& e) { // exceeded packet size cout<<"Query for '"< 512) { cerr<<"Remote "<::max()-sizeof(dnsheader)); if(type == DNSType::AXFR) { cout<<"Should do AXFR for "<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(std::out_of_range& e) { // 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"<