root/trunk/pdns/pdns/packethandler.cc @ 2101

Revision 2101, 40.5 KB (checked in by ahu, 2 years ago)

fix reload on database error on incoming notification, mostly caused by idle databases, spotted by Frank Altpeter

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2002-2011  PowerDNS.COM BV
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18#include "packetcache.hh"
19#include "utility.hh"
20#include "base32.hh"
21#include <string>
22#include <sys/types.h>
23#include <boost/algorithm/string.hpp>
24#include <boost/foreach.hpp>
25#include "dnssecinfra.hh"
26#include "dnsseckeeper.hh"
27#include "dns.hh"
28#include "dnsbackend.hh"
29#include "ueberbackend.hh"
30#include "dnspacket.hh"
31#include "nameserver.hh"
32#include "distributor.hh"
33#include "logger.hh"
34#include "arguments.hh"
35#include "packethandler.hh"
36#include "statbag.hh"
37#include "resolver.hh"
38#include "communicator.hh"
39#include "dnsproxy.hh"
40
41#if 0
42#undef DLOG
43#define DLOG(x) x
44#endif
45
46extern StatBag S;
47extern PacketCache PC; 
48extern CommunicatorClass Communicator;
49extern DNSProxy *DP;
50
51int PacketHandler::s_count;
52extern string s_programname;
53
54PacketHandler::PacketHandler():B(s_programname)
55{
56  s_count++;
57  d_doFancyRecords = (::arg()["fancy-records"]!="no");
58  d_doWildcards = (::arg()["wildcards"]!="no");
59  d_doCNAME = (::arg()["skip-cname"]=="no");
60  d_doRecursion= ::arg().mustDo("recursor");
61  d_logDNSDetails= ::arg().mustDo("log-dns-details");
62  d_doIPv6AdditionalProcessing = ::arg().mustDo("do-ipv6-additional-processing");
63}
64
65DNSBackend *PacketHandler::getBackend()
66{
67  return &B;
68}
69
70PacketHandler::~PacketHandler()
71{
72  --s_count;
73  DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
74}
75
76void PacketHandler::addRootReferral(DNSPacket* r)
77{ 
78  // nobody reads what we output, but it appears to be the magic that shuts some nameservers up
79  static const char*ips[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53", 
80                     "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
81  static char templ[40];
82  strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
83
84  // add . NS records
85  DNSResourceRecord rr;
86  rr.qtype=QType::NS;
87  rr.ttl=518400;
88  rr.d_place=DNSResourceRecord::AUTHORITY;
89 
90  for(char c='a';c<='m';++c) {
91    *templ=c;
92    rr.content=templ;
93    r->addRecord(rr);
94  }
95
96  if(pdns_iequals(::arg()["send-root-referral"], "lean"))
97     return;
98
99  // add the additional stuff
100 
101  rr.ttl=3600000;
102  rr.qtype=QType::A;
103  rr.d_place=DNSResourceRecord::ADDITIONAL;
104
105  for(char c='a';c<='m';++c) {
106    *templ=c;
107    rr.qname=templ;
108    rr.content=ips[c-'a'];
109    r->addRecord(rr);
110  }
111}
112
113int PacketHandler::findMboxFW(DNSPacket *p, DNSPacket *r, string &target)
114{
115  DNSResourceRecord rr;
116  bool wedoforward=false;
117
118  SOAData sd;
119  int zoneId;
120  if(!getAuth(p, &sd, target, &zoneId))
121    return false;
122
123  B.lookup(QType(QType::MBOXFW),string("%@")+target,p, zoneId);
124     
125  while(B.get(rr))
126    wedoforward=true;
127
128  if(wedoforward) {
129    r->clearRecords();
130    rr.content=::arg()["smtpredirector"];
131    rr.priority=25;
132    rr.ttl=7200;
133    rr.qtype=QType::MX;
134    rr.qname=target;
135   
136    r->addRecord(rr);
137  }
138
139  return wedoforward;
140}
141
142int PacketHandler::findUrl(DNSPacket *p, DNSPacket *r, string &target)
143{
144  DNSResourceRecord rr;
145
146  bool found=false;
147     
148  B.lookup(QType(QType::URL),target,p); // search for a URL before we search for an A
149       
150  while(B.get(rr)) {
151    if(!found) 
152      r->clearRecords();
153    found=true;
154    DLOG(L << "Found a URL!" << endl);
155    rr.content=::arg()["urlredirector"];
156    rr.qtype=QType::A; 
157    rr.qname=target;
158         
159    r->addRecord(rr);
160  } 
161
162  if(found) 
163    return 1;
164
165  // now try CURL
166 
167  B.lookup(QType(QType::CURL),target,p); // search for a URL before we search for an A
168     
169  while(B.get(rr)) {
170    if(!found) 
171      r->clearRecords();
172    found=true;
173    DLOG(L << "Found a CURL!" << endl);
174    rr.content=::arg()["urlredirector"];
175    rr.qtype=1; // A
176    rr.qname=target;
177    rr.ttl=300;
178    r->addRecord(rr);
179  } 
180
181  if(found)
182    return found;
183  return 0;
184}
185
186/** Returns 0 if nothing was found, -1 if an error occured or 1 if the search
187    was satisfied */
188int PacketHandler::doFancyRecords(DNSPacket *p, DNSPacket *r, string &target)
189{
190  DNSResourceRecord rr;
191  if(p->qtype.getCode()==QType::MX)  // check if this domain has smtp service from us
192    return findMboxFW(p,r,target);
193 
194  if(p->qtype.getCode()==QType::A)   // search for a URL record for an A
195    return findUrl(p,r,target);
196  return 0;
197}
198
199/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */
200int PacketHandler::doDNSKEYRequest(DNSPacket *p, DNSPacket *r, const SOAData& sd)
201{
202  if(p->qtype.getCode()!=QType::DNSKEY) 
203    return false;
204   
205  DNSResourceRecord rr;
206  bool haveOne=false;
207  DNSSECPrivateKey dpk;
208
209  DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
210  BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
211    rr.qtype=QType::DNSKEY;
212    rr.ttl=sd.default_ttl;
213    rr.qname=p->qdomain;
214    rr.content=value.first.getDNSKEY().getZoneRepresentation();
215    rr.auth=true;
216    r->addRecord(rr);
217    haveOne=true;
218  }
219  return haveOne;
220}
221
222
223/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */
224int PacketHandler::doNSEC3PARAMRequest(DNSPacket *p, DNSPacket *r, const SOAData& sd)
225{
226  if(p->qtype.getCode()!=QType::NSEC3PARAM) 
227    return false;
228
229  DNSResourceRecord rr;
230
231  NSEC3PARAMRecordContent ns3prc;
232  if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
233    rr.qtype=QType::NSEC3PARAM;
234    rr.ttl=sd.default_ttl;
235    rr.qname=p->qdomain;
236    ns3prc.d_flags = 0; // for unknown reasons, the NSEC3PARAM 'flag' always needs to be zero.
237    rr.content=ns3prc.getZoneRepresentation(); 
238    rr.auth = true;
239    r->addRecord(rr);
240    return true;
241  }
242  return false;
243}
244
245
246/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */
247int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target)
248{
249  DNSResourceRecord rr;
250 
251  // modes: anonymous, powerdns only, full, spoofed
252  const string mode=::arg()["version-string"];
253 
254  if(p->qclass == QClass::CHAOS && p->qtype.getCode()==QType::TXT && target=="version.bind") {// TXT
255    if(mode.empty() || mode=="full") 
256      rr.content="Served by POWERDNS "VERSION" $Id$";
257    else if(mode=="anonymous") {
258      r->setRcode(RCode::ServFail);
259      return 1;
260    }
261    else if(mode=="powerdns")
262      rr.content="Served by PowerDNS - http://www.powerdns.com";
263    else 
264      rr.content=mode;
265
266    rr.ttl=5;
267    rr.qname=target;
268    rr.qtype=QType::TXT; 
269    rr.qclass=QClass::CHAOS; 
270    r->addRecord(rr);
271   
272    return 1;
273  }
274  return 0;
275}
276
277/** Determines if we are authoritative for a zone, and at what level */
278bool PacketHandler::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
279{
280  string subdomain(target);
281  do {
282    if( B.getSOA( subdomain, *sd, p ) ) {
283      sd->qname = subdomain;
284      if(zoneId)
285        *zoneId = sd->domain_id;
286      return true;
287    }
288  }
289  while( chopOff( subdomain ) );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
290  return false;
291}
292
293vector<DNSResourceRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const string &target)
294{
295  vector<DNSResourceRecord> ret;
296  DNSResourceRecord rr;
297  string subdomain(target);
298  do {
299    if(subdomain == sd.qname) // stop at SOA
300      break;
301    B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
302    while(B.get(rr)) {
303      ret.push_back(rr); // this used to exclude auth NS records for some reason
304    }
305    if(!ret.empty())
306      return ret;
307  } while( chopOff( subdomain ) );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
308  return ret;
309}
310
311vector<DNSResourceRecord> PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const string &target)
312{
313  vector<DNSResourceRecord> ret;
314  DNSResourceRecord rr;
315  string subdomain(target);
316  while( chopOff( subdomain ))  {
317    B.lookup(QType(QType::ANY), "*."+subdomain, p, sd.domain_id);
318    while(B.get(rr)) {
319      if(rr.qtype == p->qtype ||rr.qtype.getCode() == QType::CNAME )
320        ret.push_back(rr);
321    }
322   
323    if(!ret.empty())
324      return ret;
325   
326    if(subdomain == sd.qname) // stop at SOA
327      break;
328  } 
329
330  return ret;
331}
332
333
334/** returns 1 in case of a straight match, 2 in case of a wildcard CNAME (groan), 0 in case of no hit */
335int PacketHandler::doWildcardRecords(DNSPacket *p, DNSPacket *r, string &target)
336{
337  DNSResourceRecord rr;
338  bool found=false, retargeted=false;
339
340  // try chopping off domains and look for wildcard matches
341
342  // *.pietje.nl IN  A 1.2.3.4
343  // pietje.nl should now NOT match, but www.pietje.nl should
344
345  string subdomain=target;
346  string::size_type pos;
347
348  while((pos=subdomain.find("."))!=string::npos) {
349    subdomain=subdomain.substr(pos+1);
350    // DLOG();
351
352    string searchstr=string("*.")+subdomain;
353
354    B.lookup(QType(QType::ANY), searchstr,p); // start our search at the backend
355
356    while(B.get(rr)) { // read results
357      if(retargeted)
358        continue;
359      found=true;
360      if((p->qtype.getCode()==QType::ANY || rr.qtype==p->qtype) || rr.qtype.getCode()==QType::CNAME) {
361        rr.qname=target;
362
363        if(d_doFancyRecords && p->qtype.getCode()==QType::ANY && (rr.qtype.getCode()==QType::URL || rr.qtype.getCode()==QType::CURL)) {
364          rr.content=::arg()["urlredirector"];
365          rr.qtype=QType::A; 
366        }
367
368        r->addRecord(rr);  // and add
369        if(rr.qtype.getCode()==QType::CNAME) {
370          if(target==rr.content) {
371            L<<Logger::Error<<"Ignoring wildcard CNAME '"<<rr.qname<<"' pointing at itself"<<endl;
372            r->setRcode(RCode::ServFail);
373            continue;
374          }
375         
376          DLOG(L<<Logger::Error<<"Retargeting because of wildcard cname, from "<<target<<" to "<<rr.content<<endl);
377         
378          target=rr.content; // retarget
379          retargeted=true;
380        }
381      }
382      else if(d_doFancyRecords && ::arg().mustDo("wildcard-url") && p->qtype.getCode()==QType::A && rr.qtype.getName()=="URL") {
383        rr.content=::arg()["urlredirector"];
384        rr.qtype=QType::A; 
385        rr.qname=target;
386       
387        r->addRecord(rr);
388      }
389    }
390    if(found) {
391      DLOG(L<<"Wildcard match on '"<<string("*.")+subdomain<<"'"<<", retargeted="<<retargeted<<endl);
392      return retargeted ? 2 : 1;
393    }
394  }
395  DLOG(L<<"Returning no hit for '"<<string("*.")+subdomain<<"'"<<endl);
396  return 0;
397}
398
399/** dangling is declared true if we were unable to resolve everything */
400int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata)
401{
402  DNSResourceRecord rr;
403  SOAData sd;
404
405  if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
406    vector<DNSResourceRecord *> arrs=r->getAPRecords();
407    if(arrs.empty()) 
408      return 1;
409
410    DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
411
412    vector<DNSResourceRecord> crrs;
413
414    for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
415        i!=arrs.end();  ++i) 
416      crrs.push_back(**i);
417
418    // we now have a copy, push_back on packet might reallocate!
419
420    for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
421        i!=crrs.end();
422        ++i) {
423     
424      if(r->d.aa && !i->qname.empty() && i->qtype.getCode()==QType::NS && !B.getSOA(i->qname,sd,p)) { // drop AA in case of non-SOA-level NS answer, except for root referral
425        r->d.aa=false;
426        //      i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
427      }
428
429      QType qtypes[2];
430      qtypes[0]="A"; qtypes[1]="AAAA";
431      for(int n=0 ; n < d_doIPv6AdditionalProcessing + 1; ++n) {
432        B.lookup(qtypes[n],i->content,p); 
433        bool foundOne=false;
434        while(B.get(rr)) {
435          foundOne=true;
436          if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
437            DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
438            continue; // not adding out-of-zone additional data
439          }
440          if(rr.auth && !endsOn(rr.qname, soadata.qname)) // don't sign out of zone data using the main key
441            rr.auth=false;
442          rr.d_place=DNSResourceRecord::ADDITIONAL;
443          r->addRecord(rr);
444        }
445      }
446    }
447  }
448  return 1;
449}
450
451
452void PacketHandler::emitNSEC(const std::string& begin, const std::string& end, const std::string& toNSEC, const SOAData& sd, DNSPacket *r, int mode)
453{
454  cerr<<"We should emit '"<<begin<<"' - ('"<<toNSEC<<"') - '"<<end<<"'"<<endl;
455  NSECRecordContent nrc;
456  nrc.d_set.insert(QType::RRSIG);
457  nrc.d_set.insert(QType::NSEC);
458  if(sd.qname == begin)
459    nrc.d_set.insert(QType::DNSKEY);
460
461  DNSResourceRecord rr;
462  rr.ttl = sd.default_ttl;
463  B.lookup(QType(QType::ANY), begin);
464  while(B.get(rr)) {
465    nrc.d_set.insert(rr.qtype.getCode());   
466  }
467 
468  nrc.d_next=end;
469
470  rr.qname=begin;
471  // we can leave ttl untouched, either it is the default, or it is what we retrieved above
472  rr.qtype=QType::NSEC;
473  rr.content=nrc.getZoneRepresentation();
474  rr.d_place = (mode == 2 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
475  rr.auth = true;
476 
477  r->addRecord(rr);
478}
479
480void emitNSEC3(DNSBackend& B, const NSEC3PARAMRecordContent& ns3prc, const SOAData& sd, const std::string& unhashed, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode)
481{
482  cerr<<"We should emit NSEC3 '"<<toLower(toBase32Hex(begin))<<"' - ('"<<toNSEC3<<"') - '"<<toLower(toBase32Hex(end))<<"' (unhashed: '"<<unhashed<<"')"<<endl;
483  NSEC3RecordContent n3rc;
484  n3rc.d_set.insert(QType::RRSIG);
485  n3rc.d_salt=ns3prc.d_salt;
486  n3rc.d_flags = ns3prc.d_flags;
487  n3rc.d_iterations = ns3prc.d_iterations;
488  n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
489
490  DNSResourceRecord rr;
491  rr.ttl = sd.default_ttl;
492  B.lookup(QType(QType::ANY), unhashed);
493  while(B.get(rr)) {
494    n3rc.d_set.insert(rr.qtype.getCode());   
495  }
496
497  if(unhashed == sd.qname) {
498    n3rc.d_set.insert(QType::NSEC3PARAM);
499    n3rc.d_set.insert(QType::DNSKEY);
500  }
501 
502  n3rc.d_nexthash=end;
503
504  rr.qname=dotConcat(toLower(toBase32Hex(begin)), sd.qname);
505 
506  rr.qtype=QType::NSEC3;
507  rr.content=n3rc.getZoneRepresentation();
508 
509  rr.d_place = (mode == 2 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
510  rr.auth = true;
511  r->addRecord(rr);
512}
513
514void PacketHandler::emitNSEC3(const NSEC3PARAMRecordContent& ns3prc, const SOAData& sd, const std::string& unhashed, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode)
515{
516  ::emitNSEC3(B, ns3prc, sd, unhashed, begin, end, toNSEC3, r, mode);
517 
518}
519
520/* mode 0 = no error -> an NSEC that starts with 'target', in authority section
521   mode 1 = NXDOMAIN -> an NSEC from auth to first + a covering NSEC
522   mode 2 = ANY or direct NSEC request  -> an NSEC that starts with 'target'
523   mode 3 = a covering NSEC in the authority section (like 1, except for first)
524*/
525void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
526{
527  NSEC3PARAMRecordContent ns3rc;
528  cerr<<"Doing NSEC3PARAM lookup for '"<<auth<<"', "<<p->qdomain<<"|"<<p->qtype.getName()<<": ";
529  bool narrow;
530  if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow))  {
531    cerr<<"Present, narrow="<<narrow<<endl;
532    addNSEC3(p, r, target, auth, ns3rc, narrow, mode);
533  }
534  else {
535    cerr<<"Not present"<<endl;
536    addNSEC(p, r, target, auth, mode);
537  }
538}
539
540static void incrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
541{
542  if(raw.empty())
543    return;
544   
545  for(string::size_type pos=raw.size(); pos; ) {
546    --pos;
547    unsigned char c = (unsigned char)raw[pos];
548    ++c;
549    raw[pos] = (char) c;
550    if(c)
551      break;
552  }
553}
554
555static void decrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
556{
557  if(raw.empty())
558    return;
559   
560  for(string::size_type pos=raw.size(); pos; ) {
561    --pos;
562    unsigned char c = (unsigned char)raw[pos];
563    --c;
564    raw[pos] = (char) c;
565    if(c != 0xff)
566      break;
567  }
568}
569
570
571bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, string& unhashed, string& before, string& after)
572{
573  bool ret;
574  if(narrow) { // nsec3-narrow
575    ret=true;
576    before=hashed;
577    if(decrement)
578      decrementHash(before);
579    after=hashed;
580    incrementHash(after);
581  }
582  else {
583    ret=db->getBeforeAndAfterNamesAbsolute(id, toLower(toBase32Hex(hashed)), unhashed, before, after);
584    before=fromBase32Hex(before);
585    after=fromBase32Hex(after);
586  }
587  // cerr<<"rgetNSEC3Hashes: "<<hashed<<", "<<unhashed<<", "<<before<<", "<<after<<endl;
588  return ret;
589}
590
591void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
592{
593  string hashed;
594 
595  SOAData sd;
596  sd.db = (DNSBackend*)-1;
597  if(!B.getSOA(auth, sd)) {
598    cerr<<"Could not get SOA for domain in NSEC3\n";
599    return;
600  }
601  // cerr<<"salt in ph: '"<<makeHexDump(ns3rc.d_salt)<<"', narrow="<<narrow<<endl;
602  string unhashed, before,after;
603
604  // now add the closest encloser
605  unhashed=auth;
606  hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
607 
608  getNSEC3Hashes(narrow, sd.db, sd.domain_id,  hashed, false, unhashed, before, after); 
609  cerr<<"Done calling for closest encloser, before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"', unhashed: '"<<unhashed<<"'"<<endl;
610  emitNSEC3(ns3rc, sd, unhashed, before, after, target, r, mode);
611
612  // now add the main nsec3
613  unhashed = p->qdomain;
614  hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
615  getNSEC3Hashes(narrow, sd.db,sd.domain_id,  hashed, true, unhashed, before, after); 
616  cerr<<"Done calling for main, before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"', unhashed: '"<<unhashed<<"'"<<endl;
617  emitNSEC3( ns3rc, sd, unhashed, before, after, target, r, mode);
618 
619  // now add the *
620  unhashed=dotConcat("*", auth);
621  hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
622 
623  getNSEC3Hashes(narrow, sd.db, sd.domain_id,  hashed, true, unhashed, before, after); 
624  cerr<<"Done calling for '*', before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"', unhashed: '"<<unhashed<<"'"<<endl;
625  emitNSEC3( ns3rc, sd, unhashed, before, after, target, r, mode);
626}
627
628void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
629{
630  if(!p->d_dnssecOk)
631    return;
632 
633  cerr<<"Should add NSEC covering '"<<target<<"' from zone '"<<auth<<"', mode = "<<mode<<endl;
634  SOAData sd;
635  sd.db=(DNSBackend *)-1; // force uncached answer
636
637  if(auth.empty()) {
638    getAuth(p, &sd, target, 0);
639  }
640  else if(!B.getSOA(auth, sd)) {
641    cerr<<"Could not get SOA for domain\n";
642    return;
643  }
644
645  string before,after;
646  cerr<<"Calling getBeforeandAfter!"<<endl;
647  sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after); 
648  cerr<<"Done calling, before='"<<before<<"', after='"<<after<<"'"<<endl;
649
650  // this stuff is wrong (but it appears to work)
651 
652  if(mode ==0 || mode==2)
653    emitNSEC(target, after, target, sd, r, mode);
654 
655  if(mode == 1)  {
656    emitNSEC(before, after, target, sd, r, mode);
657
658    sd.db->getBeforeAndAfterNames(sd.domain_id, auth, auth, before, after); 
659    emitNSEC(auth, after, auth, sd, r, mode);
660  }
661
662  if(mode == 3)
663    emitNSEC(before, after, target, sd, r, mode);
664
665  return;
666}
667
668bool PacketHandler::doDNSSECProcessing(DNSPacket *p, DNSPacket *r)
669{
670  if(!p->d_dnssecOk)
671    return false;
672
673  vector<DNSResourceRecord *> arrs=r->getAnswerRecords();
674  if(arrs.empty()) 
675    return false;
676 
677  cerr<<"Have arrs "<<arrs.size()<<" records to sign\n";
678  vector<DNSResourceRecord> crrs;
679 
680  for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
681      i!=arrs.end();    ++i) 
682    crrs.push_back(**i);
683 
684  // we now have a copy, push_back on packet might reallocate!
685 
686  for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
687      i!=crrs.end();
688      ++i) {
689    if(i->d_place!=DNSResourceRecord::ANSWER) 
690      continue;
691   
692    B.lookup(QType(QType::RRSIG),i->qname,p); 
693    DNSResourceRecord rr;
694    while(B.get(rr)) {
695      rr.d_place=DNSResourceRecord::ANSWER;
696      if(splitField(rr.content, ' ').first==i->qtype.getName())
697        r->addRecord(rr);
698    }
699  }
700 
701  return false;
702}
703
704/* returns 1 if everything is done & ready, 0 if the search should continue, 2 if a 'NO-ERROR' response should be generated */
705int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target)
706{
707  DNSResourceRecord rr;
708
709  bool found=false, rfound=false;
710
711  if(p->qtype.getCode()!=QType::CNAME && !d_doCNAME)
712    return 0;
713
714  // Traverse a CNAME chain if needed
715  for(int numloops=0;;numloops++) {
716    if(numloops==10) {
717      L<<Logger::Error<<"Detected a CNAME loop involving "<<target<<", sending SERVFAIL"<<endl;
718      r->setRcode(2);
719      return 1;
720    }
721
722    B.lookup(QType(QType::ANY),target,p);
723       
724    bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY;
725    int hits=0;
726    bool relevantNS=false;
727    bool sawDS=false;
728    bool crossedZoneCut = false;
729    while(B.get(rr)) {
730      if(rr.qtype.getCode() == QType::NS && p->qtype.getCode() != QType::NS) { // possible retargeting
731        relevantNS=true;
732      }
733
734      if(rr.qtype.getCode()==QType::DS && p->qtype.getCode() == QType::NS && p->d_dnssecOk) {
735        sawDS = true;
736        r->addRecord(rr);
737      }
738
739      if(rr.qtype.getCode()!=QType::NS || p->qtype.getCode()==QType::NS)
740        hits++;
741      if(!rfound && rr.qtype.getCode()==QType::CNAME) {
742        found=true;
743        r->addRecord(rr);
744        target=rr.content; // for retargeting
745      }
746      if(shortcut && !found && rr.qtype==p->qtype) {
747        if(!rr.auth) {
748        // no idea why this if is here
749        }
750         
751        rfound=true;
752        r->addRecord(rr);
753      }
754    }
755
756    if(crossedZoneCut) {
757      cerr<<"Should return NS records, and this A/AAAA record in the additional section.."<<endl;
758    }
759
760    if(!sawDS && p->qtype.getCode() == QType::NS && p->d_dnssecOk && rfound) {
761      addNSECX(p, r, p->qdomain, "", 2); // make it 'official' that we have no DS
762    }
763
764    if(hits && !relevantNS && !found && !rfound && shortcut ) { // XXX FIXME !numloops. we found matching qnames but not a qtype
765      DLOG(L<<"Found matching qname, but not the qtype"<<endl);
766      return 2;
767    }
768
769    if(rfound)
770      return 1; // ANY lookup found the right answer immediately
771
772    if(found) {
773      if(p->qtype.getCode()==QType::CNAME) // they really wanted a CNAME!
774        return 1;
775      DLOG(L<<"Looping because of a CNAME to "<<target<<endl);
776      found=false;
777    }
778    else 
779      break;
780  }
781
782  // we now have what we really search for ready in 'target'
783  return 0;
784}
785
786/* Semantics:
787   
788- only one backend owns the SOA of a zone
789- only one AXFR per zone at a time - double startTransaction should fail
790- backends need to implement transaction semantics
791
792
793How BindBackend would implement this:
794   startTransaction makes a file
795   feedRecord sends everything to that file
796   commitTransaction moves that file atomically over the regular file, and triggers a reload
797   rollbackTransaction removes the file
798
799
800How PostgreSQLBackend would implement this:
801   startTransaction starts a sql transaction, which also deletes all records
802   feedRecord is an insert statement
803   commitTransaction commits the transaction
804   rollbackTransaction aborts it
805
806How MySQLBackend would implement this:
807   (good question!)
808   
809*/     
810
811int PacketHandler::trySuperMaster(DNSPacket *p)
812{
813  Resolver::res_t nsset;
814  try {
815    Resolver resolver;
816    uint32_t theirserial;
817    resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial);   
818    resolver.resolve(p->getRemote(), p->qdomain.c_str(), QType::NS, &nsset);
819  }
820  catch(ResolverException &re) {
821    L<<Logger::Error<<"Error resolving SOA or NS at: "<< p->getRemote() <<": "<<re.reason<<endl;
822    return RCode::ServFail;
823  }
824
825  string account;
826  DNSBackend *db;
827  if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &account, &db)) {
828    L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<endl;
829    return RCode::Refused;
830  }
831  db->createSlaveDomain(p->getRemote(),p->qdomain,account);
832  Communicator.addSuckRequest(p->qdomain, p->getRemote()); 
833  L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<", queued axfr"<<endl;
834  return RCode::NoError;
835}
836
837int PacketHandler::processNotify(DNSPacket *p)
838{
839  /* now what?
840     was this notification from an approved address?
841     We determine our internal SOA id (via UeberBackend)
842     We determine the SOA at our (known) master
843     if master is higher -> do stuff
844  */
845  if(!::arg().mustDo("slave")) {
846    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
847    return RCode::NotImp;
848  }
849  DNSBackend *db=0;
850  DomainInfo di;
851  di.serial = 0;
852  if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
853    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
854    return trySuperMaster(p);
855  }
856   
857  if(::arg().contains("trusted-notification-proxy", p->getRemote())) {
858    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
859    if(di.masters.empty()) {
860      L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
861      return RCode::Refused;
862    }
863  }
864  else if(!db->isMaster(p->qdomain, p->getRemote())) {
865    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
866    return RCode::Refused;
867  }
868 
869 
870  // ok, we've done our checks
871  Communicator.addSlaveCheckRequest(di, p->remote);
872 
873  return 0;
874}
875
876
877
878bool validDNSName(const string &name)
879{
880  string::size_type pos, length=name.length();
881  char c;
882  for(pos=0; pos < length; ++pos) {
883    c=name[pos];
884    if(!((c >= 'a' && c <= 'z') ||
885         (c >= 'A' && c <= 'Z') ||
886         (c >= '0' && c <= '9') ||
887         c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\'))
888      return false;
889  }
890  return true;
891} 
892
893DNSPacket *PacketHandler::question(DNSPacket *p)
894{
895  bool shouldRecurse=false;
896  DNSPacket *ret=questionOrRecurse(p, &shouldRecurse);
897  if(shouldRecurse) {
898    DP->sendPacket(p);
899  }
900  return ret;
901}
902
903void PacketHandler::synthesiseRRSIGs(DNSPacket* p, DNSPacket* r)
904{
905  cerr<<"Need to fake up the RRSIGs if someone asked for them explicitly"<<endl;
906  typedef map<uint16_t, vector<shared_ptr<DNSRecordContent> > > records_t;
907  records_t records;
908
909  NSECRecordContent nrc;
910  nrc.d_set.insert(QType::RRSIG);
911  nrc.d_set.insert(QType::NSEC);
912
913  DNSResourceRecord rr;
914
915  SOAData sd;
916  sd.db=(DNSBackend *)-1; // force uncached answer
917  getAuth(p, &sd, p->qdomain, 0);
918
919  rr.ttl=sd.default_ttl;
920  B.lookup(QType(QType::ANY), p->qdomain, p);
921
922  while(B.get(rr)) {
923    if(!rr.auth) 
924      continue;
925   
926    // this deals with the 'prio' mismatch!
927    if(rr.qtype.getCode()==QType::MX || rr.qtype.getCode() == QType::SRV) { 
928      rr.content = lexical_cast<string>(rr.priority) + " " + rr.content;
929    }
930   
931    if(!rr.content.empty() && rr.qtype.getCode()==QType::TXT && rr.content[0]!='"') {
932      rr.content="\""+rr.content+"\"";
933    }
934    if(rr.content.empty())  // empty contents confuse the MOADNS setup
935      rr.content=".";
936    shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)); 
937   
938    records[rr.qtype.getCode()].push_back(drc);
939    nrc.d_set.insert(rr.qtype.getCode());
940  }
941  bool narrow;
942  NSEC3PARAMRecordContent ns3pr;
943  bool doNSEC3= d_dk.getNSEC3PARAM(sd.qname, &ns3pr, &narrow);
944  if(doNSEC3) {
945    cerr<<"We don't yet add NSEC3 to explicit RRSIG queries correctly yet! (narrow="<<narrow<<")\n";
946  }
947  else {
948    // now get the NSEC too (since we must sign it!)
949    string before,after;
950    sd.db->getBeforeAndAfterNames(sd.domain_id, sd.qname, p->qdomain, before, after); 
951 
952    nrc.d_next=after;
953 
954    rr.qname=p->qdomain;
955    // rr.ttl is already set.. we hope
956    rr.qtype=QType::NSEC;
957    rr.content=nrc.getZoneRepresentation();
958    records[QType::NSEC].push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
959 
960    // ok, the NSEC is in..
961  }
962  cerr<<"Have "<<records.size()<<" rrsets to sign"<<endl;
963
964  rr.qname = p->qdomain;
965  // again, rr.ttl is already set
966  rr.auth = 0; // please don't sign this!
967  rr.d_place = DNSResourceRecord::ANSWER;
968  rr.qtype = QType::RRSIG;
969
970  BOOST_FOREACH(records_t::value_type& iter, records) {
971    vector<RRSIGRecordContent> rrcs;
972   
973    getRRSIGsForRRSET(d_dk, sd.qname, p->qdomain, iter.first, 3600, iter.second, rrcs, iter.first == QType::DNSKEY);
974    BOOST_FOREACH(RRSIGRecordContent& rrc, rrcs) {
975      rr.content=rrc.getZoneRepresentation();
976      r->addRecord(rr);
977    }
978  }
979}
980
981void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd)
982{
983  DNSResourceRecord rr;
984  rr.qname=sd.qname;
985  rr.qtype=QType::SOA;
986  rr.content=serializeSOAData(sd);
987  rr.ttl=sd.ttl;
988  rr.domain_id=sd.domain_id;
989  rr.d_place=DNSResourceRecord::AUTHORITY;
990  rr.auth = 1;
991  r->addRecord(rr);
992 
993  if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname))
994    addNSECX(p, r, target, sd.qname, 1);
995 
996  r->setRcode(RCode::NXDomain); 
997  S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
998}
999
1000void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd)
1001{
1002  DNSResourceRecord rr;
1003  rr.qname=sd.qname;
1004  rr.qtype=QType::SOA;
1005  rr.content=serializeSOAData(sd);
1006  rr.ttl=sd.ttl;
1007  rr.domain_id=sd.domain_id;
1008  rr.d_place=DNSResourceRecord::AUTHORITY;
1009  rr.auth = 1;
1010  r->addRecord(rr);
1011
1012  if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname))
1013    addNSECX(p, r, target, sd.qname, 0);
1014
1015  S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
1016}
1017
1018
1019bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const string& dsname)
1020{
1021  //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
1022  B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
1023  DNSResourceRecord rr;
1024  bool gotOne=false;
1025  while(B.get(rr)) {
1026    gotOne=true;
1027    rr.d_place = DNSResourceRecord::AUTHORITY;
1028    rr.auth=true; // please sign it!
1029    r->addRecord(rr);
1030  }
1031  return gotOne;
1032}
1033
1034bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
1035{
1036  vector<DNSResourceRecord> rrset = getBestReferralNS(p, sd, target);
1037  if(rrset.empty())
1038    return false;
1039 
1040  cerr<<"The best NS is: "<<rrset.begin()->qname<<endl;
1041  BOOST_FOREACH(DNSResourceRecord rr, rrset) {
1042    cerr<<"\tadding '"<<rr.content<<"'\n";
1043    rr.d_place=DNSResourceRecord::AUTHORITY;
1044    r->addRecord(rr);
1045  }
1046  r->setA(false);
1047
1048  if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->qname))
1049    addNSECX(p, r, rrset.begin()->qname, sd.qname, 0);
1050 
1051  return true;
1052}
1053
1054void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
1055{
1056  if(!p->d_dnssecOk)
1057    cerr<<"Need to add all the RRSIGs too for '"<<target<<"', should do this manually since DNSSEC was not requested"<<endl;
1058  //  cerr<<"Need to add all the NSEC too.."<<endl; /// XXX FIXME THE ABOVE IF IS WEIRD
1059 
1060  if(!d_dk.isSecuredZone(sd.qname))
1061    return;
1062   
1063  addNSECX(p, r, target, sd.qname, 2); 
1064  if(pdns_iequals(sd.qname, p->qdomain)) {
1065    DNSSECKeeper::keyset_t zskset = d_dk.getKeys(p->qdomain);
1066    DNSResourceRecord rr;
1067    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
1068      rr.qtype=QType::DNSKEY;
1069      rr.ttl=sd.default_ttl;
1070      rr.qname=p->qdomain;
1071      rr.content=value.first.getDNSKEY().getZoneRepresentation();
1072      rr.auth = true;
1073      r->addRecord(rr);
1074    }
1075  }
1076}
1077
1078bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, string &target, bool& retargeted)
1079{
1080  retargeted=false;
1081
1082  vector<DNSResourceRecord> rrset = getBestWildcard(p, sd, target);
1083  if(rrset.empty())
1084    return false;
1085
1086  cerr<<"The best wildcard match: "<<rrset.begin()->qname<<endl;
1087  BOOST_FOREACH(DNSResourceRecord rr, rrset) {
1088    if(rr.qtype.getCode() == QType::CNAME)  {
1089      retargeted=true;
1090      target=rr.content;
1091    }
1092
1093    rr.wildcardname = rr.qname;
1094    rr.qname=p->qdomain;
1095    cerr<<"\tadding '"<<rr.content<<"'\n";
1096    rr.d_place=DNSResourceRecord::ANSWER;
1097    r->addRecord(rr);
1098  }
1099
1100  if(p->d_dnssecOk) {
1101    addNSECX(p, r, p->qdomain, sd.qname, 3);
1102  }
1103  return true;
1104}
1105
1106//! Called by the Distributor to ask a question. Returns 0 in case of an error
1107DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
1108{
1109  *shouldRecurse=false;
1110  DNSResourceRecord rr;
1111  SOAData sd;
1112  sd.db=0;
1113 
1114  string subdomain="";
1115  string soa;
1116  int retargetcount=0;
1117
1118  vector<DNSResourceRecord> rrset;
1119  bool weDone=0, weRedirected=0, weHaveUnauth=0;
1120
1121  DNSPacket *r=p->replyPacket();  // generate an empty reply packet
1122  bool noCache=false;
1123  if(p->d_havetsig) {
1124    string keyname, secret;
1125    TSIGRecordContent trc;
1126    if(!checkForCorrectTSIG(p, &B, &keyname, &secret, &trc)) {
1127      if(d_logDNSDetails)
1128        L<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
1129      r->setRcode(RCode::NotAuth);
1130      return r;
1131    }
1132    p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1133    noCache=true;
1134  }
1135 
1136  try {   
1137    if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1138      L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1139      S.inc("corrupt-packets");
1140      delete r;
1141      return 0;
1142    }
1143
1144    // XXX FIXME do this in DNSPacket::parse ?
1145
1146    if(!validDNSName(p->qdomain)) {
1147      if(d_logDNSDetails)
1148        L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1149      S.inc("corrupt-packets");
1150      r->setRcode(RCode::ServFail);
1151      return r;
1152    }
1153    if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1154      if(p->d.opcode==Opcode::Update) {
1155        if(::arg().mustDo("log-failed-updates"))
1156          L<<Logger::Notice<<"Received an UPDATE opcode from "<<p->getRemote()<<" for "<<p->qdomain<<", sending NOTIMP"<<endl;
1157        r->setRcode(RCode::NotImp); // notimp;
1158        return r; 
1159      }
1160      else if(p->d.opcode==Opcode::Notify) {
1161        int res=processNotify(p);
1162        if(res>=0) {
1163          r->setRcode(res);
1164          r->setOpcode(Opcode::Notify);
1165          return r;
1166        }
1167        delete r;
1168        return 0;
1169      }
1170     
1171      L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1172
1173      r->setRcode(RCode::NotImp); 
1174      return r; 
1175    }
1176
1177    // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<<endl;
1178   
1179   
1180    if(p->d.rd && d_doRecursion && DP->recurseFor(p))  // make sure we set ra if rd was set, and we'll do it
1181      r->d.ra=true;
1182
1183    if(p->qtype.getCode()==QType::IXFR) {
1184      r->setRcode(RCode::NotImp);
1185      return r;
1186    }
1187
1188    // please don't query fancy records directly!
1189    if(d_doFancyRecords && (p->qtype.getCode()==QType::URL || p->qtype.getCode()==QType::CURL || p->qtype.getCode()==QType::MBOXFW)) {
1190      r->setRcode(RCode::ServFail);
1191      return r;
1192    }
1193   
1194    string target=p->qdomain;
1195   
1196
1197    if(doVersionRequest(p,r,target)) // catch version.bind requests
1198      goto sendit;
1199
1200    if(p->qclass==255) // any class query
1201      r->setA(false);
1202    else if(p->qclass != QClass::IN) // we only know about IN, so we don't find anything
1203      goto sendit;
1204
1205  retargeted:;
1206    if(retargetcount > 10) {    // XXX FIXME, retargetcount++?
1207      r->setRcode(RCode::ServFail);
1208      return r;
1209    }
1210   
1211    if(!getAuth(p, &sd, target, 0)) {
1212      if(r->d.ra) {
1213        *shouldRecurse=true;
1214        delete r;
1215        return 0;
1216      }
1217       
1218      r->setA(false);
1219      if(::arg().mustDo("send-root-referral")) {
1220        DLOG(L<<Logger::Warning<<"Adding root-referral"<<endl);
1221        addRootReferral(r);
1222      }
1223      else {
1224        DLOG(L<<Logger::Warning<<"Adding SERVFAIL"<<endl);
1225        r->setRcode(RCode::ServFail);  // 'sorry'
1226      }
1227      goto sendit;
1228    }
1229    DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
1230    // we know we have authority
1231
1232    if(pdns_iequals(sd.qname, p->qdomain)) {
1233      if(doDNSKEYRequest(p,r, sd)) 
1234        goto sendit;
1235 
1236      if(doNSEC3PARAMRequest(p,r, sd)) 
1237        goto sendit;
1238    }
1239
1240    if(p->qtype.getCode() == QType::SOA && pdns_iequals(sd.qname, p->qdomain)) {
1241        rr.qname=sd.qname;
1242      rr.qtype=QType::SOA;
1243      rr.content=serializeSOAData(sd);
1244      rr.ttl=sd.ttl;
1245      rr.domain_id=sd.domain_id;
1246      rr.d_place=DNSResourceRecord::ANSWER;
1247      rr.auth = true;
1248      r->addRecord(rr);
1249      goto sendit;
1250    }
1251
1252    // this TRUMPS a cname!
1253    if(p->qtype.getCode() == QType::NSEC && p->d_dnssecOk && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
1254      addNSEC(p, r, target, sd.qname, 2); // only NSEC please
1255      goto sendit;
1256    }
1257   
1258    // this TRUMPS a cname!
1259    if(p->qtype.getCode() == QType::RRSIG && p->d_dnssecOk) {
1260      synthesiseRRSIGs(p, r);
1261      goto sendit; 
1262    }
1263
1264    // see what we get..
1265    B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1266    rrset.clear();
1267    weDone=weRedirected=weHaveUnauth=0;
1268   
1269    while(B.get(rr)) {
1270      if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) 
1271        weDone=1;
1272      if((rr.qtype == p->qtype || rr.qtype.getCode() == QType::NS) && !rr.auth) 
1273        weHaveUnauth=1;
1274
1275      if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME) 
1276        weRedirected=1;
1277      rrset.push_back(rr);
1278    }
1279
1280    //cerr<<"After first ANY query: weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<endl;
1281
1282    if(rrset.empty()) {
1283      // try wildcards, and if they don't work, go look for NS records
1284      cerr<<"Found nothing in the ANY, but let's try wildcards.."<<endl;
1285      bool wereRetargeted;
1286      if(tryWildcard(p, r, sd, target, wereRetargeted)) {
1287        if(wereRetargeted) {
1288          retargetcount++;
1289          goto retargeted;
1290        }
1291        goto sendit;
1292      }
1293      cerr<<"Found nothing in the ANY and wildcards, let's try NS referral"<<endl;
1294      if(!tryReferral(p, r, sd, target))
1295        makeNXDomain(p, r, target, sd);
1296
1297      goto sendit;
1298    }
1299                                       
1300    if(weRedirected) {
1301      BOOST_FOREACH(rr, rrset) {
1302        if(rr.qtype.getCode() == QType::CNAME) {
1303          r->addRecord(rr);
1304          target = rr.content;
1305          retargetcount++;
1306          goto retargeted;
1307        }
1308      }
1309         
1310    }
1311    else if(weDone) {
1312      BOOST_FOREACH(rr, rrset) {
1313        if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) 
1314          r->addRecord(rr);
1315      }
1316
1317      if(p->qtype.getCode() == QType::ANY) {
1318        completeANYRecords(p, r, sd, target);
1319      }
1320
1321      goto sendit;
1322    }
1323    else if(weHaveUnauth) {
1324      cerr<<"Have unauth data, so need to hunt for best NS records"<<endl;
1325      if(tryReferral(p, r, sd, target))
1326        goto sendit;
1327      cerr<<"Should not get here: please run pdnssec rectify-zone "<<sd.qname<<endl;
1328    }
1329    else {
1330      cerr<<"Have some data, but not the right data"<<endl;
1331      makeNOError(p, r, target, sd);
1332    }
1333   
1334  sendit:;
1335    if(doAdditionalProcessingAndDropAA(p, r, sd)<0) {
1336      delete r;
1337      return 0;
1338    }
1339
1340    //    doDNSSECProcessing(p, r);
1341
1342    if(p->d_dnssecOk)
1343      addRRSigs(d_dk, B, sd.qname, r->getRRS());
1344     
1345    // editSOA(d_dk, sd.qname, r);
1346     
1347    r->wrapup(); // needed for inserting in cache
1348    if(!noCache)
1349      PC.insert(p, r); // in the packet cache
1350  }
1351  catch(DBException &e) {
1352    L<<Logger::Error<<"Database module reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
1353    r->setRcode(RCode::ServFail);
1354    S.inc("servfail-packets");
1355    S.ringAccount("servfail-queries",p->qdomain);
1356  }
1357  catch(AhuException &e) {
1358    L<<Logger::Error<<"Database module reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
1359    r->setRcode(RCode::ServFail);
1360    S.inc("servfail-packets");
1361    S.ringAccount("servfail-queries",p->qdomain);
1362  }
1363  catch(std::exception &e) {
1364    L<<Logger::Error<<"Exception building answer packet ("<<e.what()<<") sending out servfail"<<endl;
1365    delete r;
1366    r=p->replyPacket();  // generate an empty reply packet   
1367    r->setRcode(RCode::ServFail);
1368    S.inc("servfail-packets");
1369    S.ringAccount("servfail-queries",p->qdomain);
1370  }
1371  return r; 
1372
1373}
1374
Note: See TracBrowser for help on using the browser.