lots of work, starting to look useful

This commit is contained in:
bert hubert
2018-04-09 23:04:13 +02:00
parent ab91a50402
commit 2872f88c99
7 changed files with 106 additions and 76 deletions

View File

@ -1,11 +1,9 @@
/* Goal: a fully standards compliant basic authoritative server. In <500 lines.
/* Goal: a fully standards compliant basic authoritative server. In <1000 lines.
Non-goals: notifications, slaving zones, name compression, edns,
performance
*/
#include <cstdint>
#include <string>
#include <vector>
#include <deque>
#include <map>
#include <stdexcept>
#include "sclasses.hh"
@ -18,6 +16,33 @@
using namespace std;
void addAdditional(const DNSNode* bestzone, const dnsname& zone, const vector<dnsname>& toresolve, DNSMessageWriter& response)
{
for(auto addname : toresolve ) {
cout<<"Doing additional or glue lookup for "<<addname<<endl;
if(!addname.makeRelative(zone)) {
cout<<addname<<" is not within our zone, not doing glue"<<endl;
continue;
}
dnsname wuh;
cout<<"Looking up glue record "<<addname<<" in zone "<<zone<<endl;
auto addnode = bestzone->find(addname, wuh);
if(!addnode || !addname.empty()) {
cout<<" Found nothing, continuing"<<endl;
continue;
}
for(auto& type : {DNSType::A, DNSType::AAAA}) {
auto iter2 = addnode->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
{
@ -27,14 +52,11 @@ try
cout<<"Received a query from "<<remote.toStringWithPort()<<" for "<<name<<" and type "<<type<<endl;
response.dh = dm.dh;
response.dh.ad = 0;
response.dh.ra = 0;
response.dh.aa = 0;
response.dh.ad = response.dh.ra = response.dh.aa = 0;
response.dh.qr = 1;
response.dh.ancount = response.dh.arcount = response.dh.nscount = 0;
response.setQuestion(name, type);
if(type == DNSType::AXFR) {
if(type == DNSType::AXFR || type == DNSType::IXFR) {
cout<<"Query was for AXFR or IXFR over UDP, can't do that"<<endl;
response.dh.rcode = (int)RCode::Servfail;
return true;
@ -58,6 +80,8 @@ try
bool passedZonecut=false;
int CNAMELoopCount = 0;
loopCNAME:;
passedZonecut=false;
lastnode.clear();
auto node = bestzone->find(searchname, lastnode, &passedZonecut);
if(passedZonecut)
response.dh.aa = false;
@ -81,26 +105,7 @@ try
toresolve.push_back(dynamic_cast<NameGenerator*>(rr.get())->d_name);
}
for(auto& addname : toresolve ) {
if(!addname.makeRelative(zone)) {
cout<<addname<<" is not within our zone, not doing glue"<<endl;
continue;
}
dnsname wuh;
cout<<"Looking up glue record "<<addname<<" in zone "<<zone<<endl;
auto addnode = bestzone->find(addname, wuh);
if(!addnode || !addname.empty()) {
cout<<"Found nothing, continuing"<<endl;
}
auto iter2 = addnode->rrsets.find(DNSType::A);
if(iter2 != addnode->rrsets.end()) {
cout<<"Lastnode for '"<<addname<<"' glue: "<<wuh<<endl;
const auto& rrset = iter2->second;
for(const auto& rr : rrset.contents) {
response.putRR(DNSSection::Additional, wuh+zone, DNSType::A, rrset.ttl, rr);
}
}
}
addAdditional(bestzone, zone, toresolve, response);
}
else {
cout<<"This is an NXDOMAIN situation"<<endl;
@ -123,9 +128,13 @@ try
}
else if(iter = node->rrsets.find(type), iter != node->rrsets.end()) {
const auto& rrset = iter->second;
vector<dnsname> additional;
for(const auto& rr : rrset.contents) {
response.putRR(DNSSection::Answer, lastnode+zone, type, rrset.ttl, rr);
if(type == DNSType::MX)
additional.push_back(dynamic_cast<MXGenerator*>(rr.get())->d_name);
}
addAdditional(bestzone, zone, additional, response);
}
else if(iter = node->rrsets.find(DNSType::CNAME), iter != node->rrsets.end()) {
cout<<"We do have a CNAME!"<<endl;
@ -137,8 +146,9 @@ try
}
if(target.makeRelative(zone)) {
cout<<" Should follow CNAME to "<<target<<" within our zone"<<endl;
searchname = target;
if(CNAMELoopCount++ < 10)
// XXX we need to change our behaviour on NXDOMAIN I think depending on if you've followed a CNAME
searchname = target;
if(CNAMELoopCount++ < 10)
goto loopCNAME;
}
else
@ -239,17 +249,14 @@ void tcpClientThread(ComboAddress local, ComboAddress remote, int s, const DNSNo
dnsname zone;
auto fnd = zones->find(name, zone);
if(!fnd || !fnd->zone || !name.empty()) {
cout<<" This was not a zone"<<endl;
if(!fnd || !fnd->zone || !name.empty() || !fnd->zone->rrsets.count(DNSType::SOA)) {
cout<<" This was not a zone, or zone had no SOA"<<endl;
return;
}
cout<<"Have zone, walking it"<<endl;
response.dh = dm.dh;
response.dh.ad = 0;
response.dh.ra = 0;
response.dh.aa = 0;
response.dh.ad = response.dh.ra = response.dh.aa = 0;
response.dh.qr = 1;
response.dh.ancount = response.dh.arcount = response.dh.nscount = 0;
response.setQuestion(zone, type);
auto node = fnd->zone;
@ -258,13 +265,10 @@ void tcpClientThread(ComboAddress local, ComboAddress remote, int s, const DNSNo
response.putRR(DNSSection::Answer, zone, DNSType::SOA, node->rrsets[DNSType::SOA].ttl, node->rrsets[DNSType::SOA].contents[0]);
writeTCPResponse(sock, response);
response.dh.ancount = response.dh.arcount = response.dh.nscount = 0;
response.payload.rewind();
response.setQuestion(zone, type);
// send all other records
node->visit([&response,&sock,&name,&type,&zone](const dnsname& nname, const DNSNode* n) {
cout<<nname<<", types: ";
for(const auto& p : n->rrsets) {
if(p.first == DNSType::SOA)
continue;
@ -275,20 +279,14 @@ void tcpClientThread(ComboAddress local, ComboAddress remote, int s, const DNSNo
}
catch(...) { // exceeded packet size
writeTCPResponse(sock, response);
response.dh.ancount = response.dh.arcount = response.dh.nscount = 0;
response.payload.rewind();
response.setQuestion(zone, type);
goto retry;
}
}
cout<<p.first<<" ";
}
cout<<endl;
}, zone);
writeTCPResponse(sock, response);
response.dh.ancount = response.dh.arcount = response.dh.nscount = 0;
response.payload.rewind();
response.setQuestion(zone, type);
// send SOA again
@ -312,32 +310,43 @@ void tcpClientThread(ComboAddress local, ComboAddress remote, int s, const DNSNo
void loadZones(DNSNode& zones)
{
auto zone = zones.add({"powerdns", "org"});
zone->zone = new DNSNode(); // XXX ICK
auto newzone = zone->zone = new DNSNode(); // XXX ICK
zone->zone->rrsets[DNSType::SOA].add(SOAGenerator::make({"ns1", "powerdns", "org"}, {"admin", "powerdns", "org"}, 1));
zone->zone->rrsets[DNSType::MX].add(MXGenerator::make(25, {"server1", "powerdns", "org"}));
newzone->rrsets[DNSType::SOA].add(SOAGenerator::make({"ns1", "powerdns", "org"}, {"admin", "powerdns", "org"}, 1));
newzone->rrsets[DNSType::MX].add(MXGenerator::make(25, {"server1", "powerdns", "org"}));
zone->zone->rrsets[DNSType::A].add(AGenerator::make("1.2.3.4"));
zone->zone->rrsets[DNSType::AAAA].add(AAAAGenerator::make("::1"));
zone->zone->rrsets[DNSType::AAAA].ttl= 900;
zone->zone->rrsets[DNSType::NS].add(NameGenerator::make({"ns1", "powerdns", "org"}));
newzone->rrsets[DNSType::A].add(AGenerator::make("1.2.3.4"));
newzone->rrsets[DNSType::AAAA].add(AAAAGenerator::make("::1"));
newzone->rrsets[DNSType::AAAA].ttl= 900;
newzone->rrsets[DNSType::NS].add(NameGenerator::make({"ns1", "powerdns", "org"}));
newzone->rrsets[DNSType::TXT].add(TXTGenerator::make("Proudly served by tdns " __DATE__ " " __TIME__));
zone->zone->add({"www"})->rrsets[DNSType::CNAME].add(NameGenerator::make({"server1","powerdns","org"}));
newzone->add({"www"})->rrsets[DNSType::CNAME].add(NameGenerator::make({"server1","powerdns","org"}));
newzone->add({"www2"})->rrsets[DNSType::CNAME].add(NameGenerator::make({"nosuchserver1","powerdns","org"}));
zone->zone->add({"server1"})->rrsets[DNSType::A].add(AGenerator::make("213.244.168.210"));
zone->zone->add({"server1"})->rrsets[DNSType::AAAA].add(AAAAGenerator::make("::1"));
newzone->add({"server1"})->rrsets[DNSType::A].add(AGenerator::make("213.244.168.210"));
newzone->add({"server1"})->rrsets[DNSType::AAAA].add(AAAAGenerator::make("::1"));
newzone->add({"server2"})->rrsets[DNSType::A].add(AGenerator::make("213.244.168.210"));
newzone->add({"server2"})->rrsets[DNSType::AAAA].add(AAAAGenerator::make("::1"));
// zone->zone->add({"*"})->rrsets[(dnstype)DNSType::A]={"\x05\x06\x07\x08"};
newzone->add({"*", "nl"})->rrsets[DNSType::A].add(AGenerator::make("5.6.7.8"));
newzone->add({"*", "fr"})->rrsets[DNSType::CNAME].add(NameGenerator::make({"server2", "powerdns", "org"}));
zone->zone->add({"fra"})->rrsets[DNSType::NS].add(NameGenerator::make({"ns1","fra","powerdns","org"}));
zone->zone->add({"fra"})->rrsets[DNSType::NS].add(NameGenerator::make({"ns2","fra","powerdns","org"}));
newzone->add({"fra"})->rrsets[DNSType::NS].add(NameGenerator::make({"ns1","fra","powerdns","org"}));
newzone->add({"fra"})->rrsets[DNSType::NS].add(NameGenerator::make({"ns2","fra","powerdns","org"}));
zone->zone->add({"ns1", "fra"})->rrsets[DNSType::A].add(AGenerator::make("12.13.14.15"));
zone->zone->add({"NS2", "fra"})->rrsets[DNSType::A].add(AGenerator::make("12.13.14.16"));
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"));
}
int main(int argc, char** argv)
try
{
if(argc != 2) {
cerr<<"Syntax: tdns ipaddress:port"<<endl;
return(EXIT_FAILURE);
}
signal(SIGPIPE, SIG_IGN);
ComboAddress local(argv[1], 53);
@ -361,3 +370,8 @@ int main(int argc, char** argv)
t.detach();
}
}
catch(std::exception& e)
{
cerr<<"Fatal error: "<<e.what()<<endl;
return EXIT_FAILURE;
}