/* 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 #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) { if(dm.dh.qr) { cerr<<"Dropping non-query from "<zone) { cout<<"No zone matched"<zone.get(); DNSName searchname(qname), lastnode, zonecutname; const DNSNode* passedZonecut=0; int CNAMELoopCount = 0; loopCNAME:; auto node = bestzone->find(searchname, lastnode, true, &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::Authority, zonename, DNSType::SOA, rrset.ttl, rrset.contents[0]); } addAdditional(bestzone, zonename, additional, response); } return true; } catch(std::out_of_range& e) { // exceeded packet size cout<<"Query for '"< 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.get(); // send SOA response.putRR(DNSSection::Answer, zone, DNSType::SOA, node->rrsets[DNSType::SOA].ttl, node->rrsets[DNSType::SOA].contents[0]); writeTCPMessage(sock, response); response.clearRRs(); // 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 writeTCPMessage(sock, response); response.clearRRs(); goto retry; } } } }, zone); writeTCPMessage(sock, response); response.clearRRs(); // send SOA again response.putRR(DNSSection::Answer, zone, DNSType::SOA, node->rrsets[DNSType::SOA].ttl, node->rrsets[DNSType::SOA].contents[0]); writeTCPMessage(sock, response); return; } else { if(processQuestion(*zones, dm, local, remote, response)) { writeTCPMessage(sock, response); } else return; } } } std::unique_ptr retrieveZone(const ComboAddress& remote, const DNSName& zone) { cout<<"Attempting to retrieve zone "<(); int soaCount=0; for(;;) { uint16_t len = tcpGetLen(tcp); string message = SRead(tcp, len); cout<<"Got "<(); } DNSName rrname; DNSType rrtype; DNSSection rrsection; uint32_t ttl; std::unique_ptr rr; while(dmr.getRR(rrsection, rrname, rrtype, ttl, rr)) { if(!rrname.makeRelative(zone)) continue; if(rrtype == DNSType::SOA && ++soaCount==2) goto done; cout << rrname<< " IN " << rrtype << " " << ttl << " " <toString()<add(rrname)->addRRs(std::move(rr)); ret->add(rrname)->rrsets[rrtype].ttl = ttl; } } done: cout<<"Done"<zone=retrieveZone(ComboAddress("2001:500:2f::f", 53), {}); zones.add({"hubertnet", "nl"})->zone=retrieveZone(ComboAddress("52.48.64.3", 53), {"hubertnet", "nl"}); zones.add({"ds9a", "nl"})->zone=retrieveZone(ComboAddress("52.48.64.3", 53), {"ds9a", "nl"}); */ thread udpServer(udpThread, local, &udplistener, &zones); for(;;) { ComboAddress remote(local); // so it has room for IPv6 int client = SAccept(tcplistener, remote); thread t(tcpClientThread, local, remote, client, &zones); t.detach(); } } catch(std::exception& e) { cerr<<"Fatal error: "<