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

Revision 1959, 40.7 KB (checked in by ahu, 2 years ago)

divorce addRRSigs() from DNSPacket. Make sure addRRSigs() uses an RRSIG order that is easier on the eyes.
Massively clean up the outgoing AXFR code by moving it to the ChunkedSigningPipe?. Note to self, teach it not to sign if so required ;-)

  • 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      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, const SOAData& soadata)
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          if(rr.auth && !endsOn(rr.qname, soadata.qname)) // don't sign out of zone data using the main key
442            rr.auth=false;
443          rr.d_place=DNSResourceRecord::ADDITIONAL;
444          r->addRecord(rr);
445        }
446      }
447    }
448  }
449  return 1;
450}
451
452
453void PacketHandler::emitNSEC(const std::string& begin, const std::string& end, const std::string& toNSEC, const SOAData& sd, DNSPacket *r, int mode)
454{
455  cerr<<"We should emit '"<<begin<<"' - ('"<<toNSEC<<"') - '"<<end<<"'"<<endl;
456  NSECRecordContent nrc;
457  nrc.d_set.insert(QType::RRSIG);
458  nrc.d_set.insert(QType::NSEC);
459  if(sd.qname == begin)
460    nrc.d_set.insert(QType::DNSKEY);
461
462  DNSResourceRecord rr;
463  rr.ttl = sd.default_ttl;
464  B.lookup(QType(QType::ANY), begin);
465  while(B.get(rr)) {
466    nrc.d_set.insert(rr.qtype.getCode());   
467  }
468 
469  nrc.d_next=end;
470
471  rr.qname=begin;
472  // we can leave ttl untouched, either it is the default, or it is what we retrieved above
473  rr.qtype=QType::NSEC;
474  rr.content=nrc.getZoneRepresentation();
475  rr.d_place = (mode == 2 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
476  rr.auth = true;
477 
478  r->addRecord(rr);
479}
480
481void 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)
482{
483  cerr<<"We should emit NSEC3 '"<<toLower(toBase32Hex(begin))<<"' - ('"<<toNSEC3<<"') - '"<<toLower(toBase32Hex(end))<<"' (unhashed: '"<<unhashed<<"')"<<endl;
484  NSEC3RecordContent n3rc;
485  n3rc.d_set.insert(QType::RRSIG);
486  n3rc.d_salt=ns3prc.d_salt;
487  n3rc.d_flags = ns3prc.d_flags;
488  n3rc.d_iterations = ns3prc.d_iterations;
489  n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
490
491  DNSResourceRecord rr;
492  rr.ttl = sd.default_ttl;
493  B.lookup(QType(QType::ANY), unhashed);
494  while(B.get(rr)) {
495    n3rc.d_set.insert(rr.qtype.getCode());   
496  }
497
498  if(unhashed == sd.qname) {
499    n3rc.d_set.insert(QType::NSEC3PARAM);
500    n3rc.d_set.insert(QType::DNSKEY);
501  }
502 
503  n3rc.d_nexthash=end;
504
505  rr.qname=dotConcat(toLower(toBase32Hex(begin)), sd.qname);
506 
507  rr.qtype=QType::NSEC3;
508  rr.content=n3rc.getZoneRepresentation();
509 
510  rr.d_place = (mode == 2 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
511  rr.auth = true;
512  r->addRecord(rr);
513}
514
515void 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)
516{
517  ::emitNSEC3(B, ns3prc, sd, unhashed, begin, end, toNSEC3, r, mode);
518 
519}
520
521/* mode 0 = no error -> an NSEC that starts with 'target', in authority section
522   mode 1 = NXDOMAIN -> an NSEC from auth to first + a covering NSEC
523   mode 2 = ANY or direct NSEC request  -> an NSEC that starts with 'target'
524   mode 3 = a covering NSEC in the authority section (like 1, except for first)
525*/
526void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
527{
528  NSEC3PARAMRecordContent ns3rc;
529  cerr<<"Doing NSEC3PARAM lookup for '"<<auth<<"', "<<p->qdomain<<"|"<<p->qtype.getName()<<": ";
530  bool narrow;
531  if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow))  {
532    cerr<<"Present, narrow="<<narrow<<endl;
533    addNSEC3(p, r, target, auth, ns3rc, narrow, mode);
534  }
535  else {
536    cerr<<"Not present"<<endl;
537    addNSEC(p, r, target, auth, mode);
538  }
539}
540
541static void incrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
542{
543  if(raw.empty())
544    return;
545   
546  for(string::size_type pos=raw.size(); pos; ) {
547    --pos;
548    unsigned char c = (unsigned char)raw[pos];
549    ++c;
550    raw[pos] = (char) c;
551    if(c)
552      break;
553  }
554}
555
556static void decrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
557{
558  if(raw.empty())
559    return;
560   
561  for(string::size_type pos=raw.size(); pos; ) {
562    --pos;
563    unsigned char c = (unsigned char)raw[pos];
564    --c;
565    raw[pos] = (char) c;
566    if(c != 0xff)
567      break;
568  }
569}
570
571
572bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, string& unhashed, string& before, string& after)
573{
574  bool ret;
575  if(narrow) { // nsec3-narrow
576    ret=true;
577    before=hashed;
578    if(decrement)
579      decrementHash(before);
580    after=hashed;
581    incrementHash(after);
582  }
583  else {
584    ret=db->getBeforeAndAfterNamesAbsolute(id, toLower(toBase32Hex(hashed)), unhashed, before, after);
585    before=fromBase32Hex(before);
586    after=fromBase32Hex(after);
587  }
588  // cerr<<"rgetNSEC3Hashes: "<<hashed<<", "<<unhashed<<", "<<before<<", "<<after<<endl;
589  return ret;
590}
591
592void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
593{
594  string hashed;
595 
596  SOAData sd;
597  sd.db = (DNSBackend*)-1;
598  if(!B.getSOA(auth, sd)) {
599    cerr<<"Could not get SOA for domain in NSEC3\n";
600    return;
601  }
602  // cerr<<"salt in ph: '"<<makeHexDump(ns3rc.d_salt)<<"', narrow="<<narrow<<endl;
603  string unhashed, before,after;
604
605  // now add the closest encloser
606  unhashed=auth;
607  hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
608 
609  getNSEC3Hashes(narrow, sd.db, sd.domain_id,  hashed, false, unhashed, before, after); 
610  cerr<<"Done calling for closest encloser, before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"', unhashed: '"<<unhashed<<"'"<<endl;
611  emitNSEC3(ns3rc, sd, unhashed, before, after, target, r, mode);
612
613  // now add the main nsec3
614  unhashed = p->qdomain;
615  hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
616  getNSEC3Hashes(narrow, sd.db,sd.domain_id,  hashed, true, unhashed, before, after); 
617  cerr<<"Done calling for main, before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"', unhashed: '"<<unhashed<<"'"<<endl;
618  emitNSEC3( ns3rc, sd, unhashed, before, after, target, r, mode);
619 
620  // now add the *
621  unhashed=dotConcat("*", auth);
622  hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
623 
624  getNSEC3Hashes(narrow, sd.db, sd.domain_id,  hashed, true, unhashed, before, after); 
625  cerr<<"Done calling for '*', before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"', unhashed: '"<<unhashed<<"'"<<endl;
626  emitNSEC3( ns3rc, sd, unhashed, before, after, target, r, mode);
627}
628
629void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
630{
631  if(!p->d_dnssecOk)
632    return;
633 
634  cerr<<"Should add NSEC covering '"<<target<<"' from zone '"<<auth<<"', mode = "<<mode<<endl;
635  SOAData sd;
636  sd.db=(DNSBackend *)-1; // force uncached answer
637
638  if(auth.empty()) {
639    getAuth(p, &sd, target, 0);
640  }
641  else if(!B.getSOA(auth, sd)) {
642    cerr<<"Could not get SOA for domain\n";
643    return;
644  }
645
646  string before,after;
647  cerr<<"Calling getBeforeandAfter!"<<endl;
648  sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after); 
649  cerr<<"Done calling, before='"<<before<<"', after='"<<after<<"'"<<endl;
650
651  // this stuff is wrong (but it appears to work)
652 
653  if(mode ==0 || mode==2)
654    emitNSEC(target, after, target, sd, r, mode);
655 
656  if(mode == 1)  {
657    emitNSEC(before, after, target, sd, r, mode);
658
659    sd.db->getBeforeAndAfterNames(sd.domain_id, auth, auth, before, after); 
660    emitNSEC(auth, after, auth, sd, r, mode);
661  }
662
663  if(mode == 3)
664    emitNSEC(before, after, target, sd, r, mode);
665
666  return;
667}
668
669bool PacketHandler::doDNSSECProcessing(DNSPacket *p, DNSPacket *r)
670{
671  if(!p->d_dnssecOk)
672    return false;
673
674  vector<DNSResourceRecord *> arrs=r->getAnswerRecords();
675  if(arrs.empty()) 
676    return false;
677 
678  cerr<<"Have arrs "<<arrs.size()<<" records to sign\n";
679  vector<DNSResourceRecord> crrs;
680 
681  for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
682      i!=arrs.end();    ++i) 
683    crrs.push_back(**i);
684 
685  // we now have a copy, push_back on packet might reallocate!
686 
687  for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
688      i!=crrs.end();
689      ++i) {
690    if(i->d_place!=DNSResourceRecord::ANSWER) 
691      continue;
692   
693    B.lookup(QType(QType::RRSIG),i->qname,p); 
694    DNSResourceRecord rr;
695    while(B.get(rr)) {
696      rr.d_place=DNSResourceRecord::ANSWER;
697      if(splitField(rr.content, ' ').first==i->qtype.getName())
698        r->addRecord(rr);
699    }
700  }
701 
702  return false;
703}
704
705/* returns 1 if everything is done & ready, 0 if the search should continue, 2 if a 'NO-ERROR' response should be generated */
706int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target)
707{
708  DNSResourceRecord rr;
709
710  bool found=false, rfound=false;
711
712  if(p->qtype.getCode()!=QType::CNAME && !d_doCNAME)
713    return 0;
714
715  // Traverse a CNAME chain if needed
716  for(int numloops=0;;numloops++) {
717    if(numloops==10) {
718      L<<Logger::Error<<"Detected a CNAME loop involving "<<target<<", sending SERVFAIL"<<endl;
719      r->setRcode(2);
720      return 1;
721    }
722
723    B.lookup(QType(QType::ANY),target,p);
724       
725    bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY;
726    int hits=0;
727    bool relevantNS=false;
728    bool sawDS=false;
729    bool crossedZoneCut = false;
730    while(B.get(rr)) {
731      if(rr.qtype.getCode() == QType::NS && p->qtype.getCode() != QType::NS) { // possible retargeting
732        relevantNS=true;
733      }
734
735      if(rr.qtype.getCode()==QType::DS && p->qtype.getCode() == QType::NS && p->d_dnssecOk) {
736        sawDS = true;
737        r->addRecord(rr);
738      }
739
740      if(rr.qtype.getCode()!=QType::NS || p->qtype.getCode()==QType::NS)
741        hits++;
742      if(!rfound && rr.qtype.getCode()==QType::CNAME) {
743        found=true;
744        r->addRecord(rr);
745        target=rr.content; // for retargeting
746      }
747      if(shortcut && !found && rr.qtype==p->qtype) {
748        if(!rr.auth) {
749        // no idea why this if is here
750        }
751         
752        rfound=true;
753        r->addRecord(rr);
754      }
755    }
756
757    if(crossedZoneCut) {
758      cerr<<"Should return NS records, and this A/AAAA record in the additional section.."<<endl;
759    }
760
761    if(!sawDS && p->qtype.getCode() == QType::NS && p->d_dnssecOk && rfound) {
762      addNSECX(p, r, p->qdomain, "", 2); // make it 'official' that we have no DS
763    }
764
765    if(hits && !relevantNS && !found && !rfound && shortcut ) { // XXX FIXME !numloops. we found matching qnames but not a qtype
766      DLOG(L<<"Found matching qname, but not the qtype"<<endl);
767      return 2;
768    }
769
770    if(rfound)
771      return 1; // ANY lookup found the right answer immediately
772
773    if(found) {
774      if(p->qtype.getCode()==QType::CNAME) // they really wanted a CNAME!
775        return 1;
776      DLOG(L<<"Looping because of a CNAME to "<<target<<endl);
777      found=false;
778    }
779    else 
780      break;
781  }
782
783  // we now have what we really search for ready in 'target'
784  return 0;
785}
786
787/* Semantics:
788   
789- only one backend owns the SOA of a zone
790- only one AXFR per zone at a time - double startTransaction should fail
791- backends need to implement transaction semantics
792
793
794How BindBackend would implement this:
795   startTransaction makes a file
796   feedRecord sends everything to that file
797   commitTransaction moves that file atomically over the regular file, and triggers a reload
798   rollbackTransaction removes the file
799
800
801How PostgreSQLBackend would implement this:
802   startTransaction starts a sql transaction, which also deletes all records
803   feedRecord is an insert statement
804   commitTransaction commits the transaction
805   rollbackTransaction aborts it
806
807How MySQLBackend would implement this:
808   (good question!)
809   
810*/     
811
812int PacketHandler::trySuperMaster(DNSPacket *p)
813{
814  Resolver::res_t nsset;
815  try {
816    Resolver resolver;
817    uint32_t theirserial;
818    resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial); 
819 
820    resolver.resolve(p->getRemote(),p->qdomain.c_str(), QType::NS);
821
822    nsset=resolver.result();
823  }
824  catch(ResolverException &re) {
825    L<<Logger::Error<<"Error resolving SOA or NS at: "<< p->getRemote() <<": "<<re.reason<<endl;
826    return RCode::ServFail;
827  }
828
829  string account;
830  DNSBackend *db;
831  if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &account, &db)) {
832    L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<endl;
833    return RCode::Refused;
834  }
835  db->createSlaveDomain(p->getRemote(),p->qdomain,account);
836  Communicator.addSuckRequest(p->qdomain, p->getRemote()); 
837  L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<", queued axfr"<<endl;
838  return RCode::NoError;
839}
840
841int PacketHandler::processNotify(DNSPacket *p)
842{
843  /* now what?
844     was this notification from an approved address?
845     We determine our internal SOA id (via UeberBackend)
846     We determine the SOA at our (known) master
847     if master is higher -> do stuff
848  */
849  if(!::arg().mustDo("slave")) {
850    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
851    return RCode::NotImp;
852  }
853  DNSBackend *db=0;
854  DomainInfo di;
855  di.serial = 0;
856  if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
857    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
858    return trySuperMaster(p);
859  }
860   
861  string authServer(p->getRemote());
862  if(::arg().contains("trusted-notification-proxy", p->getRemote())) {
863    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
864    if(di.masters.empty()) {
865      L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
866      return RCode::Refused;
867    }
868
869    authServer = *di.masters.begin();
870
871  }
872  else if(!db->isMaster(p->qdomain, p->getRemote())) {
873    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
874    return RCode::Refused;
875  }
876
877  uint32_t theirserial=0;
878
879  /* to quote Rusty Russell - this code is so bad that you can actually hear it suck */
880  /* this is an instant DoS, just spoof notifications from the address of the master and we block  */
881
882  Resolver resolver;
883  try {
884    resolver.getSoaSerial(authServer, p->qdomain, &theirserial);
885  }
886  catch(ResolverException& re) {
887    L<<Logger::Error<<re.reason<<endl;
888    return RCode::ServFail;
889  }
890
891  if(theirserial<=di.serial) {
892    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<< authServer <<", we are up to date: "<<
893      theirserial<<"<="<<di.serial<<endl;
894    return RCode::NoError;
895  }
896  else {
897    L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<di.id<<") from master "<<p->getRemote()<<": "<<
898      theirserial<<" > "<<di.serial<<endl;
899
900    Communicator.addSuckRequest(p->qdomain, authServer, true); // priority
901  }
902  return -1; 
903}
904
905
906
907bool validDNSName(const string &name)
908{
909  string::size_type pos, length=name.length();
910  char c;
911  for(pos=0; pos < length; ++pos) {
912    c=name[pos];
913    if(!((c >= 'a' && c <= 'z') ||
914         (c >= 'A' && c <= 'Z') ||
915         (c >= '0' && c <= '9') ||
916         c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@'))
917      return false;
918  }
919  return true;
920} 
921
922DNSPacket *PacketHandler::question(DNSPacket *p)
923{
924  bool shouldRecurse=false;
925  DNSPacket *ret=questionOrRecurse(p, &shouldRecurse);
926  if(shouldRecurse) {
927    DP->sendPacket(p);
928  }
929  return ret;
930}
931
932void PacketHandler::synthesiseRRSIGs(DNSPacket* p, DNSPacket* r)
933{
934  cerr<<"Need to fake up the RRSIGs if someone asked for them explicitly"<<endl;
935  typedef map<uint16_t, vector<shared_ptr<DNSRecordContent> > > records_t;
936  records_t records;
937
938  NSECRecordContent nrc;
939  nrc.d_set.insert(QType::RRSIG);
940  nrc.d_set.insert(QType::NSEC);
941
942  DNSResourceRecord rr;
943
944  SOAData sd;
945  sd.db=(DNSBackend *)-1; // force uncached answer
946  getAuth(p, &sd, p->qdomain, 0);
947
948  rr.ttl=sd.default_ttl;
949  B.lookup(QType(QType::ANY), p->qdomain, p);
950
951  while(B.get(rr)) {
952    if(!rr.auth) 
953      continue;
954   
955    // this deals with the 'prio' mismatch!
956    if(rr.qtype.getCode()==QType::MX || rr.qtype.getCode() == QType::SRV) { 
957      rr.content = lexical_cast<string>(rr.priority) + " " + rr.content;
958    }
959   
960    if(!rr.content.empty() && rr.qtype.getCode()==QType::TXT && rr.content[0]!='"') {
961      rr.content="\""+rr.content+"\"";
962    }
963    if(rr.content.empty())  // empty contents confuse the MOADNS setup
964      rr.content=".";
965    shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)); 
966   
967    records[rr.qtype.getCode()].push_back(drc);
968    nrc.d_set.insert(rr.qtype.getCode());
969  }
970  bool narrow;
971  NSEC3PARAMRecordContent ns3pr;
972  bool doNSEC3= d_dk.getNSEC3PARAM(sd.qname, &ns3pr, &narrow);
973  if(doNSEC3) {
974    cerr<<"We don't yet add NSEC3 to explicit RRSIG queries correctly yet! (narrow="<<narrow<<")\n";
975  }
976  else {
977    // now get the NSEC too (since we must sign it!)
978    string before,after;
979    sd.db->getBeforeAndAfterNames(sd.domain_id, sd.qname, p->qdomain, before, after); 
980 
981    nrc.d_next=after;
982 
983    rr.qname=p->qdomain;
984    // rr.ttl is already set.. we hope
985    rr.qtype=QType::NSEC;
986    rr.content=nrc.getZoneRepresentation();
987    records[QType::NSEC].push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
988 
989    // ok, the NSEC is in..
990  }
991  cerr<<"Have "<<records.size()<<" rrsets to sign"<<endl;
992
993  rr.qname = p->qdomain;
994  // again, rr.ttl is already set
995  rr.auth = 0; // please don't sign this!
996  rr.d_place = DNSResourceRecord::ANSWER;
997  rr.qtype = QType::RRSIG;
998
999  BOOST_FOREACH(records_t::value_type& iter, records) {
1000    vector<RRSIGRecordContent> rrcs;
1001   
1002    getRRSIGsForRRSET(d_dk, sd.qname, p->qdomain, iter.first, 3600, iter.second, rrcs, iter.first == QType::DNSKEY);
1003    BOOST_FOREACH(RRSIGRecordContent& rrc, rrcs) {
1004      rr.content=rrc.getZoneRepresentation();
1005      r->addRecord(rr);
1006    }
1007  }
1008}
1009
1010void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd)
1011{
1012  DNSResourceRecord rr;
1013  rr.qname=sd.qname;
1014  rr.qtype=QType::SOA;
1015  rr.content=serializeSOAData(sd);
1016  rr.ttl=sd.ttl;
1017  rr.domain_id=sd.domain_id;
1018  rr.d_place=DNSResourceRecord::AUTHORITY;
1019  rr.auth = 1;
1020  r->addRecord(rr);
1021 
1022  if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname))
1023    addNSECX(p, r, target, sd.qname, 1);
1024 
1025  r->setRcode(RCode::NXDomain); 
1026  S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
1027}
1028
1029void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd)
1030{
1031  DNSResourceRecord rr;
1032  rr.qname=sd.qname;
1033  rr.qtype=QType::SOA;
1034  rr.content=serializeSOAData(sd);
1035  rr.ttl=sd.ttl;
1036  rr.domain_id=sd.domain_id;
1037  rr.d_place=DNSResourceRecord::AUTHORITY;
1038  rr.auth = 1;
1039  r->addRecord(rr);
1040
1041  if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname))
1042    addNSECX(p, r, target, sd.qname, 0);
1043
1044  S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
1045}
1046
1047
1048bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const string& dsname)
1049{
1050  //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
1051  B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
1052  DNSResourceRecord rr;
1053  bool gotOne=false;
1054  while(B.get(rr)) {
1055    gotOne=true;
1056    rr.d_place = DNSResourceRecord::AUTHORITY;
1057    rr.auth=true; // please sign it!
1058    r->addRecord(rr);
1059  }
1060  return gotOne;
1061}
1062
1063bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
1064{
1065  vector<DNSResourceRecord> rrset = getBestReferralNS(p, sd, target);
1066  if(rrset.empty())
1067    return false;
1068 
1069  cerr<<"The best NS is: "<<rrset.begin()->qname<<endl;
1070  BOOST_FOREACH(DNSResourceRecord rr, rrset) {
1071    cerr<<"\tadding '"<<rr.content<<"'\n";
1072    rr.d_place=DNSResourceRecord::AUTHORITY;
1073    r->addRecord(rr);
1074  }
1075  r->setA(false);
1076
1077  if(p->d_dnssecOk && d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->qname))
1078    addNSECX(p, r, rrset.begin()->qname, sd.qname, 0);
1079 
1080  return true;
1081}
1082
1083void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
1084{
1085  if(!p->d_dnssecOk)
1086    cerr<<"Need to add all the RRSIGs too for '"<<target<<"', should do this manually since DNSSEC was not requested"<<endl;
1087  //  cerr<<"Need to add all the NSEC too.."<<endl; /// XXX FIXME THE ABOVE IF IS WEIRD
1088 
1089  if(!d_dk.isSecuredZone(sd.qname))
1090    return;
1091   
1092  addNSECX(p, r, target, sd.qname, 2); 
1093  if(pdns_iequals(sd.qname, p->qdomain)) {
1094    DNSSECKeeper::keyset_t zskset = d_dk.getKeys(p->qdomain);
1095    DNSResourceRecord rr;
1096    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
1097      rr.qtype=QType::DNSKEY;
1098      rr.ttl=sd.default_ttl;
1099      rr.qname=p->qdomain;
1100      rr.content=value.first.getDNSKEY().getZoneRepresentation();
1101      rr.auth = true;
1102      r->addRecord(rr);
1103    }
1104  }
1105}
1106
1107bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, string &target, bool& retargeted)
1108{
1109  retargeted=false;
1110
1111  vector<DNSResourceRecord> rrset = getBestWildcard(p, sd, target);
1112  if(rrset.empty())
1113    return false;
1114
1115  cerr<<"The best wildcard match: "<<rrset.begin()->qname<<endl;
1116  BOOST_FOREACH(DNSResourceRecord rr, rrset) {
1117    if(rr.qtype.getCode() == QType::CNAME)  {
1118      retargeted=true;
1119      target=rr.content;
1120    }
1121
1122    rr.wildcardname = rr.qname;
1123    rr.qname=p->qdomain;
1124    cerr<<"\tadding '"<<rr.content<<"'\n";
1125    rr.d_place=DNSResourceRecord::ANSWER;
1126    r->addRecord(rr);
1127  }
1128
1129  if(p->d_dnssecOk) {
1130    addNSECX(p, r, p->qdomain, sd.qname, 3);
1131  }
1132  return true;
1133}
1134
1135
1136//! Called by the Distributor to ask a question. Returns 0 in case of an error
1137DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
1138{
1139  *shouldRecurse=false;
1140  DNSResourceRecord rr;
1141  SOAData sd;
1142  sd.db=0;
1143 
1144  string subdomain="";
1145  string soa;
1146  int retargetcount=0;
1147
1148  vector<DNSResourceRecord> rrset;
1149  bool weDone=0, weRedirected=0, weHaveUnauth=0;
1150
1151  DNSPacket *r=0;
1152  try {   
1153    if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1154      L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1155      S.inc("corrupt-packets");
1156      return 0;
1157    }
1158
1159    // XXX FIXME do this in DNSPacket::parse ?
1160
1161    if(!validDNSName(p->qdomain)) {
1162      if(d_logDNSDetails)
1163        L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1164      S.inc("corrupt-packets");
1165      r=p->replyPacket(); 
1166      r->setRcode(RCode::ServFail);
1167      return r;
1168    }
1169    if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1170      if(p->d.opcode==Opcode::Update) {
1171        if(::arg().mustDo("log-failed-updates"))
1172          L<<Logger::Notice<<"Received an UPDATE opcode from "<<p->getRemote()<<" for "<<p->qdomain<<", sending NOTIMP"<<endl;
1173        r=p->replyPacket(); 
1174        r->setRcode(RCode::NotImp); // notimp;
1175        return r; 
1176      }
1177      else if(p->d.opcode==Opcode::Notify) {
1178        int res=processNotify(p);
1179        if(res>=0) {
1180          DNSPacket *r=p->replyPacket();
1181          r->setRcode(res);
1182          r->setOpcode(Opcode::Notify);
1183          return r;
1184        }
1185        return 0;
1186      }
1187     
1188      L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1189
1190      r=p->replyPacket(); 
1191      r->setRcode(RCode::NotImp); 
1192      return r; 
1193    }
1194
1195    // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<<endl;
1196   
1197    r=p->replyPacket();  // generate an empty reply packet
1198    if(p->d.rd && d_doRecursion && DP->recurseFor(p))  // make sure we set ra if rd was set, and we'll do it
1199      r->d.ra=true;
1200
1201    if(p->qtype.getCode()==QType::IXFR) {
1202      r->setRcode(RCode::NotImp);
1203      return r;
1204    }
1205
1206    // please don't query fancy records directly!
1207    if(d_doFancyRecords && (p->qtype.getCode()==QType::URL || p->qtype.getCode()==QType::CURL || p->qtype.getCode()==QType::MBOXFW)) {
1208      r->setRcode(RCode::ServFail);
1209      return r;
1210    }
1211   
1212    string target=p->qdomain;
1213    // bool noCache=false;
1214
1215    if(doVersionRequest(p,r,target)) // catch version.bind requests
1216      goto sendit;
1217
1218    if(p->qclass==255) // any class query
1219      r->setA(false);
1220    else if(p->qclass != QClass::IN) // we only know about IN, so we don't find anything
1221      goto sendit;
1222
1223  retargeted:;
1224    if(retargetcount > 10) {    // XXX FIXME, retargetcount++?
1225      r->setRcode(RCode::ServFail);
1226      return r;
1227    }
1228   
1229    if(!getAuth(p, &sd, target, 0)) {
1230      if(r->d.ra) {
1231        *shouldRecurse=true;
1232        delete r;
1233        return 0;
1234      }
1235       
1236      r->setA(false);
1237      if(::arg().mustDo("send-root-referral")) {
1238        DLOG(L<<Logger::Warning<<"Adding root-referral"<<endl);
1239        addRootReferral(r);
1240      }
1241      else {
1242        DLOG(L<<Logger::Warning<<"Adding SERVFAIL"<<endl);
1243        r->setRcode(RCode::ServFail);  // 'sorry'
1244      }
1245      goto sendit;
1246    }
1247    DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
1248    // we know we have authority
1249
1250    if(pdns_iequals(sd.qname, p->qdomain)) {
1251      if(doDNSKEYRequest(p,r, sd)) 
1252        goto sendit;
1253 
1254      if(doNSEC3PARAMRequest(p,r, sd)) 
1255        goto sendit;
1256    }
1257
1258    if(p->qtype.getCode() == QType::SOA && pdns_iequals(sd.qname, p->qdomain)) {
1259        rr.qname=sd.qname;
1260      rr.qtype=QType::SOA;
1261      rr.content=serializeSOAData(sd);
1262      rr.ttl=sd.ttl;
1263      rr.domain_id=sd.domain_id;
1264      rr.d_place=DNSResourceRecord::ANSWER;
1265      rr.auth = true;
1266      r->addRecord(rr);
1267      goto sendit;
1268    }
1269
1270    // this TRUMPS a cname!
1271    if(p->qtype.getCode() == QType::NSEC && p->d_dnssecOk && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
1272      addNSEC(p, r, target, sd.qname, 2); // only NSEC please
1273      goto sendit;
1274    }
1275   
1276    // this TRUMPS a cname!
1277    if(p->qtype.getCode() == QType::RRSIG && p->d_dnssecOk) {
1278      synthesiseRRSIGs(p, r);
1279      goto sendit; 
1280    }
1281
1282    // see what we get..
1283    B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1284    rrset.clear();
1285    weDone=weRedirected=weHaveUnauth=0;
1286   
1287    while(B.get(rr)) {
1288      if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) 
1289        weDone=1;
1290      if((rr.qtype == p->qtype || rr.qtype.getCode() == QType::NS) && !rr.auth) 
1291        weHaveUnauth=1;
1292
1293      if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME) 
1294        weRedirected=1;
1295      rrset.push_back(rr);
1296    }
1297
1298    //cerr<<"After first ANY query: weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<endl;
1299
1300    if(rrset.empty()) {
1301      // try wildcards, and if they don't work, go look for NS records
1302      cerr<<"Found nothing in the ANY, but let's try wildcards.."<<endl;
1303      bool wereRetargeted;
1304      if(tryWildcard(p, r, sd, target, wereRetargeted)) {
1305        if(wereRetargeted) {
1306          retargetcount++;
1307          goto retargeted;
1308        }
1309        goto sendit;
1310      }
1311      cerr<<"Found nothing in the ANY and wildcards, let's try NS referral"<<endl;
1312      if(!tryReferral(p, r, sd, target))
1313        makeNXDomain(p, r, target, sd);
1314
1315      goto sendit;
1316    }
1317                                       
1318    if(weRedirected) {
1319      BOOST_FOREACH(rr, rrset) {
1320        if(rr.qtype.getCode() == QType::CNAME) {
1321          r->addRecord(rr);
1322          target = rr.content;
1323          retargetcount++;
1324          goto retargeted;
1325        }
1326      }
1327         
1328    }
1329    else if(weDone) {
1330      BOOST_FOREACH(rr, rrset) {
1331        if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) 
1332          r->addRecord(rr);
1333      }
1334
1335      if(p->qtype.getCode() == QType::ANY) {
1336        completeANYRecords(p, r, sd, target);
1337      }
1338
1339      goto sendit;
1340    }
1341    else if(weHaveUnauth) {
1342      cerr<<"Have unauth data, so need to hunt for best NS records"<<endl;
1343      if(tryReferral(p, r, sd, target))
1344        goto sendit;
1345      cerr<<"Should not get here: please run pdnssec rectify-zone "<<sd.qname<<endl;
1346    }
1347    else {
1348      cerr<<"Have some data, but not the right data"<<endl;
1349      makeNOError(p, r, target, sd);
1350    }
1351   
1352  sendit:;
1353    if(doAdditionalProcessingAndDropAA(p, r, sd)<0)
1354      return 0;
1355
1356    //    doDNSSECProcessing(p, r);
1357
1358    if(p->d_dnssecOk)
1359      addRRSigs(d_dk, B, sd.qname, r->getRRS());
1360    r->wrapup(); // needed for inserting in cache
1361    PC.insert(p, r); // in the packet cache
1362  }
1363  catch(DBException &e) {
1364    L<<Logger::Error<<"Database module reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
1365    r->setRcode(RCode::ServFail);
1366    S.inc("servfail-packets");
1367    S.ringAccount("servfail-queries",p->qdomain);
1368  }
1369  catch(std::exception &e) {
1370    L<<Logger::Error<<"Exception building answer packet ("<<e.what()<<") sending out servfail"<<endl;
1371    delete r;
1372    r=p->replyPacket();  // generate an empty reply packet   
1373    r->setRcode(RCode::ServFail);
1374    S.inc("servfail-packets");
1375    S.ringAccount("servfail-queries",p->qdomain);
1376  }
1377  return r; 
1378
1379}
1380
Note: See TracBrowser for help on using the browser.