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

Revision 1893, 40.2 KB (checked in by ahu, 2 years ago)

implement 'pdnssec set-presigned', allowing PowerDNSSEC to serve pre-signed zones. Rather experimental, but does appear to work

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