lots of work, starting to look useful
This commit is contained in:
134
tdns/tdns.cc
134
tdns/tdns.cc
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user