[Pdns-users] CNAME confusion?!

Andreas Mimz dnsadmin at kos2.de
Thu Jan 20 10:51:11 UTC 2005


So after a couple of days I have to say that the replaced file works 
perfectly :-) No more wrong CNAME mappings (even with AAAA-Questions)! 
No other problems occured so far... (or atleast I didn't notice ;-))

Thank you very much!


bert hubert wrote:

>Ok, that probably won't work (patch issues, subversion migration leftover),
>and a thinko.
>
>Try replacing packethandler.cc in pdns 2.9.17 by the attached version.
>
>
>On Sat, Jan 15, 2005 at 03:08:11PM +0100, bert hubert wrote:
>  
>
>>Can you try this patch? It is entirely untested, but it might solve the
>>problem. Wiebren, your problem too I think.
>>
>>    
>>
>
>------------------------------------------------------------------------
>
>/*
>    PowerDNS Versatile Database Driven Nameserver
>    Copyright (C) 2005  PowerDNS.COM BV
>
>    This program is free software; you can redistribute it and/or modify
>    it under the terms of the GNU General Public License as published by
>    the Free Software Foundation; either version 2 of the License, or
>    (at your option) any later version.
>
>    This program is distributed in the hope that it will be useful,
>    but WITHOUT ANY WARRANTY; without even the implied warranty of
>    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>    GNU General Public License for more details.
>
>    You should have received a copy of the GNU General Public License
>    along with this program; if not, write to the Free Software
>    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
>*/
>#include "utility.hh"
>#include <string>
>#include <sys/types.h>
>
>#include "dns.hh"
>#include "dnsbackend.hh"
>#include "ueberbackend.hh"
>#include "dnspacket.hh"
>#include "nameserver.hh"
>#include "distributor.hh"
>#include "logger.hh"
>#include "arguments.hh"
>#include "packethandler.hh"
>#include "statbag.hh"
>#include "resolver.hh"
>#include "communicator.hh"
>#include "dnsproxy.hh"
>
>extern StatBag S;
>extern PacketCache PC;  
>extern CommunicatorClass Communicator;
>extern DNSProxy *DP;
>
>int PacketHandler::s_count;
>extern string s_programname;
>
>PacketHandler::PacketHandler():B(s_programname)
>{
>  s_count++;
>  d_doFancyRecords = (arg()["fancy-records"]!="no");
>  d_doWildcards = (arg()["wildcards"]!="no");
>  d_doCNAME = (arg()["skip-cname"]=="no");
>  d_doRecursion= arg().mustDo("recursor");
>  d_logDNSDetails= arg().mustDo("log-dns-details");
>  d_doIPv6AdditionalProcessing = arg().mustDo("do-ipv6-additional-processing");
>}
>
>DNSBackend *PacketHandler::getBackend()
>{
>  return &B;
>}
>
>PacketHandler::~PacketHandler()
>{
>  --s_count;
>  DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
>}
>
>
>int PacketHandler::findMboxFW(DNSPacket *p, DNSPacket *r, string &target)
>{
>  DNSResourceRecord rr;
>  bool wedoforward=false;
>
>  SOAData sd;
>  int zoneId;
>  if(!getAuth(p, &sd, target, &zoneId))
>    return false;
>
>  B.lookup("MBOXFW",string("%@")+target,p, zoneId);
>      
>  while(B.get(rr))
>    wedoforward=true;
>
>  if(wedoforward) {
>    rr.content=arg()["smtpredirector"];
>    rr.priority=25;
>    rr.ttl=7200;
>    rr.qtype=QType::MX;
>    rr.qname=target;
>    
>    r->addRecord(rr);
>  }
>
>  return wedoforward;
>}
>
>int PacketHandler::findUrl(DNSPacket *p, DNSPacket *r, string &target)
>{
>  DNSResourceRecord rr;
>
>  bool found=false;
>      
>  B.lookup("URL",target,p); // search for a URL before we search for an A
>        
>  while(B.get(rr)) {
>    found=true;
>    DLOG(L << "Found a URL!" << endl);
>    rr.content=arg()["urlredirector"];
>    rr.qtype=QType::A; 
>    rr.qname=target;
>	  
>    r->addRecord(rr);
>  }  
>
>  if(found)
>    return 1;
>      
>  // now try CURL
>  
>  B.lookup("CURL",target,p); // search for a URL before we search for an A
>      
>  while(B.get(rr)) {
>    found=true;
>    DLOG(L << "Found a CURL!" << endl);
>    rr.content=arg()["urlredirector"];
>    rr.qtype=1; // A
>    rr.qname=target;
>    rr.ttl=300;
>    r->addRecord(rr);
>  }  
>
>  if(found)
>    return found;
>  return 0;
>}
>
>/** Returns 0 if nothing was found, -1 if an error occured or 1 if the search
>    was satisfied */
>int PacketHandler::doFancyRecords(DNSPacket *p, DNSPacket *r, string &target)
>{
>  DNSResourceRecord rr;
>
>  if(p->qtype.getCode()==QType::MX)  // check if this domain has smtp service from us
>    return findMboxFW(p,r,target);
>  
>  if(p->qtype.getCode()==QType::A)   // search for a URL record for an A
>    return findUrl(p,r,target);
>
>  return 0;
>}
>
>int PacketHandler::doDNSCheckRequest(DNSPacket *p, DNSPacket *r, string &target)
>{
>  int result = 0;
>  DNSResourceRecord rr;
>
>  if (p->qclass == 3 && p->qtype.getName() == "HINFO") {
>    rr.content = "PowerDNS $Id: packethandler.cc 266 2005-01-11 19:41:11Z ahu $";
>    rr.ttl = 5;
>    rr.qname=target;
>    rr.qtype=13; // hinfo
>    r->addRecord(rr);
>    result = 1;
>  }
>  
>  return result;
>}
>
>/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */
>int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target)
>{
>  DNSResourceRecord rr;
>  
>  // modes: anonymous, powerdns only, full, spoofed
>  const string mode=arg()["version-string"];
>  if(p->qtype.getCode()==QType::TXT && target=="version.bind") {// TXT
>    if(mode.empty() || mode=="full") 
>      rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc 266 2005-01-11 19:41:11Z ahu $";
>    else if(mode=="anonymous") {
>      r->setRcode(RCode::ServFail);
>      return 1;
>    }
>    else if(mode=="powerdns")
>      rr.content="Served by PowerDNS - http://www.powerdns.com";
>    else 
>      rr.content=mode;
>
>    rr.ttl=5;
>    rr.qname=target;
>    rr.qtype=QType::TXT; // TXT
>    r->addRecord(rr);
>    
>    return 1;
>  }
>  return 0;
>}
>
>/** Determines if we are authoritative for a zone, and at what level */
>bool PacketHandler::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
>{
>  string subdomain(target);
>  do {
>    if( B.getSOA( subdomain, *sd ) ) {
>      sd->qname = subdomain;
>      *zoneId = sd->domain_id;
>      return true;
>    }
>  }
>  while( chopOff( subdomain ) );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
>  return false;
>}
>
>/** returns 1 in case of a straight match, 2 in case of a wildcard CNAME (groan), 0 in case of no hit */
>int PacketHandler::doWildcardRecords(DNSPacket *p, DNSPacket *r, string &target)
>{
>  DNSResourceRecord rr;
>  bool found=false, retargeted=false;
>
>  // try chopping off domains and look for wildcard matches
>
>  // *.pietje.nl IN  A 1.2.3.4
>  // pietje.nl should now NOT match, but www.pietje.nl should
>
>  string subdomain=target;
>  string::size_type pos;
>  while((pos=subdomain.find("."))!=string::npos) {
>    subdomain=subdomain.substr(pos+1);
>    // DLOG();
>
>    string searchstr=string("*.")+subdomain;
>
>    B.lookup(QType(QType::ANY), searchstr,p); // start our search at the backend
>
>    while(B.get(rr)) { // read results
>      found=true;
>      if((p->qtype.getCode()==QType::ANY || rr.qtype==p->qtype) || rr.qtype.getCode()==QType::CNAME) {
>	rr.qname=target;
>	r->addRecord(rr);  // and add
>	if(rr.qtype.getCode()==QType::CNAME) {
>	  if(target==rr.content) {
>	    L<<Logger::Error<<"Ignoring wildcard CNAME '"<<rr.qname<<"' pointing at itself"<<endl;
>	    r->setRcode(RCode::ServFail);
>	    continue;
>	  }
>	  
>	  DLOG(L<<Logger::Error<<"Retargeting because of wildcard cname, from "<<target<<" to "<<rr.content<<endl);
>	  
>	  target=rr.content; // retarget 
>	  retargeted=true;
>	}
>      }
>      else if(d_doFancyRecords && arg().mustDo("wildcard-url") && p->qtype.getCode()==QType::A && rr.qtype.getName()=="URL") {
>	rr.content=arg()["urlredirector"];
>	rr.qtype=QType::A; 
>	rr.qname=target;
>	
>	r->addRecord(rr);
>      }
>    }
>    if(found) {
>      DLOG(L<<"Wildcard match on '"<<string("*.")+subdomain<<"'"<<endl);
>      return retargeted ? 2 : 1;
>    }
>  }
>  return 0;
>}
>
>/** dangling is declared true if we were unable to resolve everything */
>int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r)
>{
>  DNSResourceRecord rr;
>  SOAData sd;
>
>  if(p->qtype.getCode()!=QType::AXFR && r->needAP()) { // this packet needs additional processing
>    DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
>
>    vector<DNSResourceRecord *> arrs=r->getAPRecords();
>    vector<DNSResourceRecord> crrs;
>
>    for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
>	i!=arrs.end();	++i) 
>      crrs.push_back(**i);
>
>    // we now have a copy, push_back on packet might reallocate!
>
>    for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
>	i!=crrs.end();
>	++i) {
>      
>      if(i->qtype.getCode()==QType::NS && !B.getSOA(i->qname,sd)) { // drop AA in case of non-SOA-level NS answer
>	r->d.aa=false;
>	//	i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
>      }
>
>      QType qtypes[2];
>      qtypes[0]="A"; qtypes[1]="AAAA";
>      for(int n=0;n < d_doIPv6AdditionalProcessing + 1; ++n) {
>	B.lookup(qtypes[n],i->content,p);  
>	bool foundOne=false;
>	while(B.get(rr)) {
>	  foundOne=true;
>	  if(rr.domain_id!=i->domain_id && arg()["out-of-zone-additional-processing"]=="no") {
>	    DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
>	    continue; // not adding out-of-zone additional data
>	  }
>	  
>	  rr.d_place=DNSResourceRecord::ADDITIONAL;
>	  r->addRecord(rr);
>	  
>	}
>	if(!foundOne) {
>	  if(d_doRecursion && DP->recurseFor(p)) {
>	    try {
>	      Resolver resolver;
>	      resolver.resolve(arg()["recursor"],i->content.c_str(),QType::A);
>	      Resolver::res_t res=resolver.result();
>	      for(Resolver::res_t::const_iterator j=res.begin();j!=res.end();++j) {
>		if(j->d_place==DNSResourceRecord::ANSWER) {
>		  rr=*j;
>		  rr.d_place=DNSResourceRecord::ADDITIONAL;
>		  r->addRecord(rr);
>		}
>	      }
>	    }
>	    catch(ResolverException& re) {
>	      // L<<Logger::Error<<"Trying to do additional processing for answer to '"<<p->qdomain<<"' query: "<<re.reason<<endl;
>	    }
>	  }
>	}
>      }
>    }
>  }
>  return 1;
>}
>
>/* returns 1 if everything is done & ready, 0 if the search should continue */
>int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target)
>{
>  DNSResourceRecord rr;
>
>  bool found=false, rfound=false;
>
>  if(p->qtype.getCode()!=QType::CNAME && !d_doCNAME)
>    return 0;
>
>  // Traverse a CNAME chain if needed
>  for(int numloops=0;;numloops++) {
>    if(numloops==10) {
>      L<<Logger::Error<<"Detected a CNAME loop involving "<<target<<", sending SERVFAIL"<<endl;
>      r->setRcode(2);
>      return 1;
>    }
>
>    B.lookup(QType(QType::ANY),target,p);
>        
>    bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY;
>    unsigned hits=0;
>    while(B.get(rr)) {
>       hits++;
>      if(!rfound && rr.qtype.getCode()==QType::CNAME) {
>	found=true;
>	r->addRecord(rr);
>	target=rr.content; // for retargeting
>      }
>      if(shortcut && !found && rr.qtype==p->qtype) {
>	rfound=true;
>	r->addRecord(rr);
>      }
>    }
>    if( (p->qtype.getCode()!=QType::SOA && hits) || rfound)
>      return 1; // ANY lookup found the right answer immediately
>
>    if(found) {
>      if(p->qtype.getCode()==QType::CNAME) // they really wanted a CNAME!
>	return 1;
>      DLOG(L<<"Looping because of a CNAME to "<<target<<endl);
>      found=false;
>    }
>    else break;
>  }
>
>  // we now have what we really search for ready in 'target'
>  return 0;
>}
>
>/* Semantics:
>   
>- only one backend owns the SOA of a zone
>- only one AXFR per zone at a time - double startTransaction should fail
>- backends need to implement transaction semantics
>
>
>How BindBackend would implement this:
>   startTransaction makes a file 
>   feedRecord sends everything to that file 
>   commitTransaction moves that file atomically over the regular file, and triggers a reload
>   rollbackTransaction removes the file
>
>
>How PostgreSQLBackend would implement this:
>   startTransaction starts a sql transaction, which also deletes all records
>   feedRecord is an insert statement
>   commitTransaction commits the transaction
>   rollbackTransaction aborts it
>
>How MySQLBackend would implement this:
>   (good question!)
>   
>*/     
>
>int PacketHandler::trySuperMaster(DNSPacket *p)
>{
>  Resolver::res_t nsset;
>  try {
>    Resolver resolver;
>    u_int32_t theirserial;
>    int res=resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial);  
>    if(res<=0) {
>      L<<Logger::Error<<"Unable to determine SOA serial for "<<p->qdomain<<" at potential supermaster "<<p->getRemote()<<endl;
>      return RCode::ServFail;
>    }
>  
>    resolver.resolve(p->getRemote(),p->qdomain.c_str(), QType::NS);
>
>    nsset=resolver.result();
>  }
>  catch(ResolverException &re) {
>    L<<Logger::Error<<"Error resolving SOA or NS for '"<<p->qdomain<<"' at "<<p->getRemote()<<endl;
>    return RCode::ServFail;
>  }
>
>  string account;
>  DNSBackend *db;
>  if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &account, &db)) {
>   L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<endl;
>    return RCode::Refused;
>  }
>  db->createSlaveDomain(p->getRemote(),p->qdomain,account);
>  Communicator.addSuckRequest(p->qdomain, p->getRemote());  
>  L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<", queued axfr"<<endl;
>  return RCode::NoError;
>}
>
>int PacketHandler::processNotify(DNSPacket *p)
>{
>  /* now what? 
>     was this notification from an approved address?
>     We determine our internal SOA id (via UeberBackend)
>     We determine the SOA at our (known) master
>     if master is higher -> do stuff
>  */
>  if(!arg().mustDo("slave")) {
>    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
>    return RCode::NotImp;
>  }
>  DNSBackend *db=0;
>  DomainInfo di;
>  if(!B.getDomainInfo(p->qdomain,di) || !(db=di.backend)) {
>    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
>    return trySuperMaster(p);
>  }
>    
>  if(!db->isMaster(p->qdomain, p->getRemote())) {
>    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
>    return RCode::Refused;
>  }
>
>  u_int32_t theirserial=0;
>
>  /* to quote Rusty Russell - this code is so bad that you can actually hear it suck */
>  /* this is an instant DoS, just spoof notifications from the address of the master and we block  */
>
>  Resolver resolver;
>  int res=resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial);
>  if(res<=0) {
>    L<<Logger::Error<<"Unable to determine SOA serial for "<<p->qdomain<<" at "<<p->getRemote()<<endl;
>    return RCode::ServFail;
>  }
>	
>
>  if(theirserial<=di.serial) {
>    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from master "<<p->getRemote()<<", we are up to date: "<<
>      theirserial<<"<="<<di.serial<<endl;
>    return RCode::NoError;
>  }
>  else {
>    L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<di.id<<") from master "<<p->getRemote()<<": "<<
>      theirserial<<" > "<<di.serial<<endl;
>
>    Communicator.addSuckRequest(p->qdomain, p->getRemote(),true); // priority
>  }
>  return -1; 
>}
>
>
>//! Called by the Distributor to ask a question. Returns 0 in case of an error
>DNSPacket *PacketHandler::question(DNSPacket *p)
>{
>  DNSResourceRecord rr;
>  SOAData sd;
>  sd.db=0;
>  
>  string subdomain="";
>  string soa;
>  int retargetcount=0;
>  bool noSameLevelNS;
>
>  DNSPacket *r=0;
>  try {    
>    DLOG(L << Logger::Notice<<"Remote "<<inet_ntoa( reinterpret_cast< struct sockaddr_in * >( &( p->remote ))->sin_addr )<<" wants a type " << p->qtype.getName() << " ("<<p->qtype.getCode()<<") about '"<<p->qdomain << "'" << endl);
>
>// XXX FIXME Find out why this isn't working!
>#ifndef WIN32
>    if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
>      L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
>      S.inc("corrupt-packets");
>      return 0;
>    }
>#endif // WIN32
>
>    // XXX FIXME do this in DNSPacket::parse ?
>
>    if(!p->qdomain.empty() && p->qdomain.find_first_of("%|")!=string::npos) {
>      L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': dropping"<<endl;
>      S.inc("corrupt-packets");
>      return 0;
>    }
>    if(p->d.opcode) { // non-zero opcode (again thanks RA!)
>      if(p->d.opcode==Opcode::Update) {
>	if(arg().mustDo("log-failed-updates"))
>	  L<<Logger::Notice<<"Received an UPDATE opcode from "<<p->getRemote()<<" for "<<p->qdomain<<", sending NOTIMP"<<endl;
>	r=p->replyPacket(); 
>	r->setRcode(RCode::NotImp); // notimp;
>	return r; 
>      }
>      else if(p->d.opcode==Opcode::Notify) {
>	int res=processNotify(p);
>	if(res>=0) {
>	  DNSPacket *r=p->replyPacket();
>	  r->setRcode(res);
>	  return r;
>	}
>	return 0;
>      }
>      
>      L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
>
>      r=p->replyPacket(); 
>      r->setRcode(RCode::NotImp); 
>      return r; 
>    }
>    
>    r=p->replyPacket();  // generate an empty reply packet
>
>    if(p->qtype.getCode()==QType::IXFR) {
>      r->setRcode(RCode::NotImp);
>      return r;
>    }
>
>    bool found=false;
>    
>    string target=p->qdomain;
>    
>    if (doDNSCheckRequest(p, r, target))
>      goto sendit;
>    
>    if(doVersionRequest(p,r,target)) // catch version.bind requests
>      goto sendit;
>
>    if(p->qclass==255) // any class query 
>      r->setA(false);
>    else if(p->qclass!=1) // we only know about IN, so we don't find anything
>      goto sendit;
>
>  retargeted:;
>    if(retargetcount++>10) {
>      L<<Logger::Error<<"Detected wildcard CNAME loop involving '"<<target<<"'"<<endl;
>      r->setRcode(RCode::ServFail);
>      goto sendit;
>    }
>
>    if(makeCanonic(p,r,target)>0) // traverse CNAME chain until we have a useful record (may actually give the correct answer!)
>      goto sendit; // this might be the end of it (client requested a CNAME, or we found the answer already)
>    
>    if(d_doFancyRecords) { // MBOXFW, URL <- fake records, emulated with MX and A
>      int res=doFancyRecords(p,r,target);
>      if(res) { // had a result
>	if(res<0) // it was an error
>	  r->setRcode(RCode::ServFail);
>	goto sendit;  
>      }
>    }
>    
>    // now ready to start the real direct search
>
>    if(p->qtype.getCode()==QType::SOA || p->qtype.getCode()==QType::ANY) { // this is special
>
>      if(B.getSOA(target,sd)) {
>	rr.qname=target;
>	rr.qtype=QType::SOA;
>	rr.content=DNSPacket::serializeSOAData(sd);
>	rr.ttl=sd.ttl;
>	rr.domain_id=sd.domain_id;
>	rr.d_place=DNSResourceRecord::ANSWER;
>	r->addRecord(rr);
>	if(p->qtype.getCode()==QType::SOA) { // we are done
>	  goto sendit;
>	}
>      }
>    }
>
>    noSameLevelNS=true;
>
>    if(p->qtype.getCode()!=QType::SOA) { // regular direct lookup
>      B.lookup(QType(QType::ANY), target,p);
>      
>      while(B.get(rr)) {
>	if(rr.qtype.getCode()==QType::SOA) // skip any direct SOA responses as they may be different
>	  continue;
>	if(rr.qtype==p->qtype || p->qtype.getCode()==QType::ANY ) {
>	  DLOG(L<<"Found a direct answer: "<<rr.content<<endl);
>	  found=true;
>	  r->addRecord(rr);  // and add
>	}
>	else
>	  if(rr.qtype.getCode()==QType::NS)
>	    noSameLevelNS=false;
>      }
>      
>      if(p->qtype.getCode()==QType::ANY) {
>	if(d_doFancyRecords) { 
>	  int res=findMboxFW(p,r,target);
>	  if(res<0)
>	    L<<Logger::Error<<"Error finding a mailbox record after an ANY query"<<endl;
>	  if(res>0) {
>	    DLOG(L<<Logger::Error<<"Frobbed an MX in!"<<endl);
>	    found=true;
>	  }
>	}
>      }
>      if(found) 
>	goto sendit;
>      
>    }
>    
>    // not found yet, try wildcards (we only try here in case of recursion - we should check before we hand off)
>
>    if(p->d.rd && d_doRecursion && d_doWildcards) { 
>      int res=doWildcardRecords(p,r,target);
>      if(res) { // had a result
>	// FIXME: wildCard may retarget us in the future
>	if(res==1)  // had a straight result
>	  goto sendit;  
>	if(res==2)
>	  goto retargeted;
>	goto sendit;  
>      }
>    }
>
>    // RECURSION CUT-OUT! 
>
>
>    bool weAuth;
>    int zoneId;
>    zoneId=-1;
>    
>    if(p->d.rd && d_doRecursion && arg().mustDo("allow-recursion-override"))
>      weAuth=getAuth(p, &sd, target, &zoneId);
>    else
>      weAuth=false;
>
>    if(p->d.rd && d_doRecursion && !weAuth && DP->sendPacket(p)) {
>      delete r;
>      return 0;
>    }
>
>    string::size_type pos;
>    
>    DLOG(L<<"Nothing found so far for '"<<target<<"', do we even have authority over this domain?"<<endl);
>
>    if(zoneId==-1)
>      weAuth=getAuth(p, &sd, target, &zoneId); // TLDAuth perhaps
>
>    if(weAuth) {
>      DLOG(L<<Logger::Warning<<"Soa found: "<<soa<<endl);
>      ;
>    }
>    if(!weAuth) {
>      if(p->d.rd || target==p->qdomain) { // only servfail if we didn't follow a CNAME
>	if(d_logDNSDetails)
>	  L<<Logger::Warning<<"Not authoritative for '"<< target<<"', sending servfail to "<<
>	    p->getRemote()<< (p->d.rd ? " (recursion was desired)" : "") <<endl;
>
>	r->setA(false);
>	r->setRcode(RCode::ServFail);  // 'sorry' - this is where we might send out a root referral
>      }
>				       
>      S.ringAccount("unauth-queries",p->qdomain+"/"+p->qtype.getName());
>      S.ringAccount("remotes-unauth",p->getRemote());
>    }
>    else {
>      DLOG(L<<Logger::Warning<<"We ARE authoritative for a subdomain of '"<<target<<"' ("<<sd.qname<<"), perhaps we have a suitable NS record then"<<endl);
>      subdomain=target;
>      found=0;
>      pos=0; 
>      
>      do {
>	if(pos) // skip dot
>	  pos++;
>	
>	subdomain=subdomain.substr(pos);
>	if(noSameLevelNS) { // skip first lookup if it is known not to exist
>	  noSameLevelNS=false;
>	  continue;
>	}
>	  
>	if(!Utility::strcasecmp(subdomain.c_str(),sd.qname.c_str())) // about to break out of our zone
>	  break; 
>
>	B.lookup("NS", subdomain,p,zoneId);  // start our search at the backend
>	
>	while(B.get(rr)) {
>	  found=true;
>	  rr.d_place=DNSResourceRecord::AUTHORITY; // this for the authority section
>	  r->addRecord(rr);
>	}
>	if(found || (!subdomain.empty() && subdomain[0]=='.')) {  // this catches '..'
>	  r->setA(false);  // send out an NS referral, which should be unauth
>	  break;
>	}
>      }while((pos=subdomain.find("."))!=string::npos);
>      
>      if(!found) {
>	// try wildcards then 
>	if(d_doWildcards) { 
>	  int res=doWildcardRecords(p,r,target);
>
>	  if(res==1)  // had a straight result
>	    goto sendit; 
>	  if(res==2)
>	    goto retargeted;
>	}
>
>	// we have authority but no answer, so we add the SOA for negative caching
>	rr.qname=sd.qname;
>	rr.qtype=QType::SOA;
>	rr.content=DNSPacket::serializeSOAData(sd);
>	rr.ttl=sd.ttl;
>	rr.domain_id=sd.domain_id;
>	rr.d_place=DNSResourceRecord::AUTHORITY;
>	r->addRecord(rr);
>
>
>	// need to send NXDOMAIN if there are 0 records for whatever type for target
>	
>	B.lookup("ANY",target,p);
>	while(B.get(rr))
>	  found=true;
>	
>	if(!found) {
>	  SOAData sd2;
>	  if(B.getSOA(target,sd2)) // is there a SOA perhaps? (which may not appear in an ANY query)
>	    found=true;
>	}
>
>	if(!found) { 
>	  if(d_logDNSDetails)
>	    L<<Logger::Notice<<"Authoritative NXDOMAIN to "<< p->getRemote() <<" for '"<<target<<"' ("<<p->qtype.getName()<<")"<<endl;
>
>	  r->setRcode(RCode::NXDomain); 
>	  S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
>	}
>	else {
>	  if(d_logDNSDetails)
>	    L<<Logger::Notice<<"Authoritative empty NO ERROR to "<< p->getRemote() <<" for '"<<target<<"' ("<<p->qtype.getName()<<"), other types do exist"<<endl;
>	  S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
>	}
>      }
>    }
>    
>    // whatever we've built so far, do additional processing
>    
>  sendit:;
>
>    if(doAdditionalProcessingAndDropAA(p,r)<0)
>      return 0;
>    
>
>    
>    
>
>    r->wrapup(); // needed for inserting in cache
>    PC.insert(p,r); // in the packet cache
>  }
>  catch(DBException &e) {
>    L<<Logger::Error<<"Database module reported condition which prevented lookup - sending out servfail"<<endl;
>    r->setRcode(RCode::ServFail);
>    S.inc("servfail-packets");
>    S.ringAccount("servfail-queries",p->qdomain);
>  }
>  return r; 
>
>}
>
>  
>




More information about the Pdns-users mailing list