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

Revision 1799, 38.1 KB (checked in by ahu, 2 years ago)

also include DNSKEY on a case-insensitive match.
Lowercase RRDATA properly for signing -> hopefully gets us 0x20 compliant

  • 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-2010  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)
202{
203  if(p->qtype.getCode()!=QType::DNSKEY) 
204    return false;
205   
206  DNSResourceRecord rr;
207  bool haveOne=false;
208  DNSSECPrivateKey dpk;
209
210  if(d_dk.haveActiveKSKFor(p->qdomain, &dpk)) {
211    rr.qtype=QType::DNSKEY;
212    rr.ttl=3600;
213    rr.qname=p->qdomain;
214    rr.content=dpk.getDNSKEY().getZoneRepresentation(); 
215    rr.auth = true;
216    r->addRecord(rr);
217    haveOne=true;
218  }
219
220  DNSSECKeeper::keyset_t zskset = d_dk.getKeys(p->qdomain, false);
221  BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
222    rr.qtype=QType::DNSKEY;
223    rr.ttl=3600;
224    rr.qname=p->qdomain;
225    rr.content=value.first.getDNSKEY().getZoneRepresentation();
226   
227    r->addRecord(rr);
228    haveOne=true;
229  }
230  return haveOne;
231}
232
233
234/** This catches DNSKEY requests. Returns 1 if it was handled, 0 if it wasn't */
235int PacketHandler::doNSEC3PARAMRequest(DNSPacket *p, DNSPacket *r)
236{
237  if(p->qtype.getCode()!=QType::NSEC3PARAM) 
238    return false;
239
240  DNSResourceRecord rr;
241
242  NSEC3PARAMRecordContent ns3prc;
243  if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
244    rr.qtype=QType::NSEC3PARAM;
245    rr.ttl=3600;
246    rr.qname=p->qdomain;
247    rr.content=ns3prc.getZoneRepresentation(); 
248    rr.auth = true;
249    r->addRecord(rr);
250    return true;
251  }
252  return false;
253}
254
255
256/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */
257int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target)
258{
259  DNSResourceRecord rr;
260 
261  // modes: anonymous, powerdns only, full, spoofed
262  const string mode=::arg()["version-string"];
263 
264  if(p->qclass == QClass::CHAOS && p->qtype.getCode()==QType::TXT && target=="version.bind") {// TXT
265    if(mode.empty() || mode=="full") 
266      rr.content="Served by POWERDNS "VERSION" $Id$";
267    else if(mode=="anonymous") {
268      r->setRcode(RCode::ServFail);
269      return 1;
270    }
271    else if(mode=="powerdns")
272      rr.content="Served by PowerDNS - http://www.powerdns.com";
273    else 
274      rr.content=mode;
275
276    rr.ttl=5;
277    rr.qname=target;
278    rr.qtype=QType::TXT; 
279    rr.qclass=QClass::CHAOS; 
280    r->addRecord(rr);
281   
282    return 1;
283  }
284  return 0;
285}
286
287/** Determines if we are authoritative for a zone, and at what level */
288bool PacketHandler::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
289{
290  string subdomain(target);
291  do {
292    if( B.getSOA( subdomain, *sd, p ) ) {
293      sd->qname = subdomain;
294      if(zoneId)
295        *zoneId = sd->domain_id;
296      return true;
297    }
298  }
299  while( chopOff( subdomain ) );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
300  return false;
301}
302
303vector<DNSResourceRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const string &target)
304{
305  vector<DNSResourceRecord> ret;
306  DNSResourceRecord rr;
307  string subdomain(target);
308  do {
309    if(subdomain == sd.qname) // stop at SOA
310      break;
311    B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
312    while(B.get(rr)) {
313      if(!rr.auth)
314        ret.push_back(rr);
315    }
316    if(!ret.empty())
317      return ret;
318  } while( chopOff( subdomain ) );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
319  return ret;
320}
321
322vector<DNSResourceRecord> PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const string &target)
323{
324  vector<DNSResourceRecord> ret;
325  DNSResourceRecord rr;
326  string subdomain(target);
327  while( chopOff( subdomain ))  {
328    B.lookup(QType(QType::ANY), "*."+subdomain, p, sd.domain_id);
329    while(B.get(rr)) {
330      if(rr.qtype == p->qtype ||rr.qtype.getCode() == QType::CNAME )
331        ret.push_back(rr);
332    }
333   
334    if(!ret.empty())
335      return ret;
336   
337    if(subdomain == sd.qname) // stop at SOA
338      break;
339  } 
340
341  return ret;
342}
343
344
345/** returns 1 in case of a straight match, 2 in case of a wildcard CNAME (groan), 0 in case of no hit */
346int PacketHandler::doWildcardRecords(DNSPacket *p, DNSPacket *r, string &target)
347{
348  DNSResourceRecord rr;
349  bool found=false, retargeted=false;
350
351  // try chopping off domains and look for wildcard matches
352
353  // *.pietje.nl IN  A 1.2.3.4
354  // pietje.nl should now NOT match, but www.pietje.nl should
355
356  string subdomain=target;
357  string::size_type pos;
358
359  while((pos=subdomain.find("."))!=string::npos) {
360    subdomain=subdomain.substr(pos+1);
361    // DLOG();
362
363    string searchstr=string("*.")+subdomain;
364
365    B.lookup(QType(QType::ANY), searchstr,p); // start our search at the backend
366
367    while(B.get(rr)) { // read results
368      if(retargeted)
369        continue;
370      found=true;
371      if((p->qtype.getCode()==QType::ANY || rr.qtype==p->qtype) || rr.qtype.getCode()==QType::CNAME) {
372        rr.qname=target;
373
374        if(d_doFancyRecords && p->qtype.getCode()==QType::ANY && (rr.qtype.getCode()==QType::URL || rr.qtype.getCode()==QType::CURL)) {
375          rr.content=::arg()["urlredirector"];
376          rr.qtype=QType::A; 
377        }
378
379        r->addRecord(rr);  // and add
380        if(rr.qtype.getCode()==QType::CNAME) {
381          if(target==rr.content) {
382            L<<Logger::Error<<"Ignoring wildcard CNAME '"<<rr.qname<<"' pointing at itself"<<endl;
383            r->setRcode(RCode::ServFail);
384            continue;
385          }
386         
387          DLOG(L<<Logger::Error<<"Retargeting because of wildcard cname, from "<<target<<" to "<<rr.content<<endl);
388         
389          target=rr.content; // retarget
390          retargeted=true;
391        }
392      }
393      else if(d_doFancyRecords && ::arg().mustDo("wildcard-url") && p->qtype.getCode()==QType::A && rr.qtype.getName()=="URL") {
394        rr.content=::arg()["urlredirector"];
395        rr.qtype=QType::A; 
396        rr.qname=target;
397       
398        r->addRecord(rr);
399      }
400    }
401    if(found) {
402      DLOG(L<<"Wildcard match on '"<<string("*.")+subdomain<<"'"<<", retargeted="<<retargeted<<endl);
403      return retargeted ? 2 : 1;
404    }
405  }
406  DLOG(L<<"Returning no hit for '"<<string("*.")+subdomain<<"'"<<endl);
407  return 0;
408}
409
410/** dangling is declared true if we were unable to resolve everything */
411int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r)
412{
413  DNSResourceRecord rr;
414  SOAData sd;
415
416  if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
417    vector<DNSResourceRecord *> arrs=r->getAPRecords();
418    if(arrs.empty()) 
419      return 1;
420
421    DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
422
423    vector<DNSResourceRecord> crrs;
424
425    for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
426        i!=arrs.end();  ++i) 
427      crrs.push_back(**i);
428
429    // we now have a copy, push_back on packet might reallocate!
430
431    for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
432        i!=crrs.end();
433        ++i) {
434     
435      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
436        r->d.aa=false;
437        //      i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
438      }
439
440      QType qtypes[2];
441      qtypes[0]="A"; qtypes[1]="AAAA";
442      for(int n=0 ; n < d_doIPv6AdditionalProcessing + 1; ++n) {
443        B.lookup(qtypes[n],i->content,p); 
444        bool foundOne=false;
445        while(B.get(rr)) {
446          foundOne=true;
447          if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
448            DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
449            continue; // not adding out-of-zone additional data
450          }
451         
452          rr.d_place=DNSResourceRecord::ADDITIONAL;
453          r->addRecord(rr);
454        }
455      }
456    }
457  }
458  return 1;
459}
460
461
462void PacketHandler::emitNSEC(const std::string& begin, const std::string& end, const std::string& toNSEC, const std::string& auth, DNSPacket *r, int mode)
463{
464  cerr<<"We should emit '"<<begin<<"' - ('"<<toNSEC<<"') - '"<<end<<"'"<<endl;
465  NSECRecordContent nrc;
466  nrc.d_set.insert(QType::RRSIG);
467  nrc.d_set.insert(QType::NSEC);
468  if(auth==begin)
469    nrc.d_set.insert(QType::DNSKEY);
470
471  DNSResourceRecord rr;
472  B.lookup(QType(QType::ANY), begin);
473  while(B.get(rr)) {
474    nrc.d_set.insert(rr.qtype.getCode());   
475  }
476 
477  nrc.d_next=end;
478
479  rr.qname=begin;
480  rr.ttl=3600;
481  rr.qtype=QType::NSEC;
482  rr.content=nrc.getZoneRepresentation();
483  rr.d_place = (mode == 2 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
484  rr.auth = true;
485  r->addRecord(rr);
486}
487
488void PacketHandler::emitNSEC3(const NSEC3PARAMRecordContent& ns3prc, const std::string& auth, const std::string& unhashed, const std::string& begin, const std::string& end, const std::string& toNSEC3, DNSPacket *r, int mode)
489{
490  cerr<<"We should emit NSEC3 '"<<toLower(toBase32Hex(begin))<<"' - ('"<<toNSEC3<<"') - '"<<toLower(toBase32Hex(end))<<"' (unhashed: '"<<unhashed<<"')"<<endl;
491  NSEC3RecordContent n3rc;
492  n3rc.d_set.insert(QType::RRSIG);
493  n3rc.d_salt=ns3prc.d_salt;
494  n3rc.d_flags = 0;
495  n3rc.d_iterations = ns3prc.d_iterations;
496  n3rc.d_algorithm = 1; // ?
497
498  DNSResourceRecord rr;
499  B.lookup(QType(QType::ANY), unhashed);
500  while(B.get(rr)) {
501    n3rc.d_set.insert(rr.qtype.getCode());   
502  }
503
504  if(unhashed == auth) {
505    n3rc.d_set.insert(QType::NSEC3PARAM);
506    n3rc.d_set.insert(QType::DNSKEY);
507  }
508 
509  n3rc.d_nexthash=end;
510
511  rr.qname=dotConcat(toLower(toBase32Hex(begin)), auth);
512  rr.ttl=3600;
513  rr.qtype=QType::NSEC3;
514  rr.content=n3rc.getZoneRepresentation();
515  cerr<<"nsec3: '"<<rr.content<<"'"<<endl;
516  rr.d_place = (mode == 2 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
517  rr.auth = true;
518  r->addRecord(rr);
519}
520
521
522
523
524/* mode 0 = no error -> an NSEC that starts with 'target', in authority section
525   mode 1 = NXDOMAIN -> an NSEC from auth to first + a covering NSEC
526   mode 2 = ANY or direct NSEC request  -> an NSEC that starts with 'target'
527   mode 3 = a covering NSEC in the authority section (like 1, except for first)
528*/
529void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
530{
531  NSEC3PARAMRecordContent ns3rc;
532  cerr<<"Doing NSEC3PARAM lookup for '"<<auth<<"', "<<p->qdomain<<"|"<<p->qtype.getName()<<": ";
533  if(d_dk.getNSEC3PARAM(auth, &ns3rc))  {
534    cerr<<"Present"<<endl;
535    addNSEC3(p, r, target, auth, ns3rc, mode);
536  }
537  else {
538    cerr<<"Not present"<<endl;
539    addNSEC(p, r, target, auth, mode);
540  }
541}
542
543void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, const NSEC3PARAMRecordContent& ns3rc, int mode)
544{
545  string hashed;
546 
547  SOAData sd;
548  sd.db = (DNSBackend*)-1;
549  if(!B.getSOA(auth, sd)) {
550    cerr<<"Could not get SOA for domain in NSEC3\n";
551    return;
552  }
553  cerr<<"salt in ph: '"<<makeHexDump(ns3rc.d_salt)<<"'"<<endl;
554  string unhashed, before,after;
555 
556  // now add the closest encloser
557  hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, auth)));
558  sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id,  hashed, unhashed, before, after); 
559  cerr<<"Done calling for closest encloser, before='"<<before<<"', after='"<<after<<"'"<<endl;
560  emitNSEC3(ns3rc, auth, unhashed, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
561 
562  // now add the main nsec3
563  hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, p->qdomain)));
564  sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id,  hashed, unhashed, before, after); 
565  cerr<<"Done calling for main, before='"<<before<<"', after='"<<after<<"'"<<endl;
566  emitNSEC3( ns3rc, auth, unhashed, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
567 
568 
569  // now add the *
570  hashed=toLower(toBase32Hex(hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, dotConcat("*", auth))));
571  sd.db->getBeforeAndAfterNamesAbsolute(sd.domain_id,  hashed, unhashed, before, after); 
572  cerr<<"Done calling for '*', before='"<<before<<"', after='"<<after<<"'"<<endl;
573  emitNSEC3( ns3rc, auth, unhashed, fromBase32Hex(before), fromBase32Hex(after), target, r, mode);
574}
575
576void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const string& target, const string& auth, int mode)
577{
578  if(!p->d_dnssecOk)
579    return;
580 
581  cerr<<"Should add NSEC covering '"<<target<<"' from zone '"<<auth<<"', mode = "<<mode<<endl;
582  SOAData sd;
583  sd.db=(DNSBackend *)-1; // force uncached answer
584
585  if(auth.empty()) {
586    getAuth(p, &sd, target, 0);
587  }
588  else if(!B.getSOA(auth, sd)) {
589    cerr<<"Could not get SOA for domain\n";
590    return;
591  }
592
593  string before,after;
594  cerr<<"Calling getBeforeandAfter!"<<endl;
595  sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after); 
596  cerr<<"Done calling, before='"<<before<<"', after='"<<after<<"'"<<endl;
597
598  // this stuff is wrong
599 
600  if(mode ==0 || mode==2)
601    emitNSEC(target, after, target, auth, r, mode);
602 
603
604  if(mode == 1)  {
605    emitNSEC(before, after, target, auth, r, mode);
606
607    sd.db->getBeforeAndAfterNames(sd.domain_id, auth, auth, before, after); 
608    emitNSEC(auth, after, auth, auth, r, mode);
609  }
610
611  if(mode == 3)
612    emitNSEC(before, after, target, auth, r, mode);
613
614  return;
615}
616
617bool PacketHandler::doDNSSECProcessing(DNSPacket *p, DNSPacket *r)
618{
619  if(!p->d_dnssecOk)
620    return false;
621
622  vector<DNSResourceRecord *> arrs=r->getAnswerRecords();
623  if(arrs.empty()) 
624    return false;
625 
626  cerr<<"Have arrs "<<arrs.size()<<" records to sign\n";
627  vector<DNSResourceRecord> crrs;
628 
629  for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
630      i!=arrs.end();    ++i) 
631    crrs.push_back(**i);
632 
633  // we now have a copy, push_back on packet might reallocate!
634 
635  for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
636      i!=crrs.end();
637      ++i) {
638    if(i->d_place!=DNSResourceRecord::ANSWER) 
639      continue;
640   
641    B.lookup(QType(QType::RRSIG),i->qname,p); 
642    DNSResourceRecord rr;
643    while(B.get(rr)) {
644      rr.d_place=DNSResourceRecord::ANSWER;
645      if(splitField(rr.content, ' ').first==i->qtype.getName())
646        r->addRecord(rr);
647    }
648  }
649 
650  return false;
651}
652
653/* returns 1 if everything is done & ready, 0 if the search should continue, 2 if a 'NO-ERROR' response should be generated */
654int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target)
655{
656  DNSResourceRecord rr;
657
658  bool found=false, rfound=false;
659
660  if(p->qtype.getCode()!=QType::CNAME && !d_doCNAME)
661    return 0;
662
663  // Traverse a CNAME chain if needed
664  for(int numloops=0;;numloops++) {
665    if(numloops==10) {
666      L<<Logger::Error<<"Detected a CNAME loop involving "<<target<<", sending SERVFAIL"<<endl;
667      r->setRcode(2);
668      return 1;
669    }
670
671    B.lookup(QType(QType::ANY),target,p);
672       
673    bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY;
674    int hits=0;
675    bool relevantNS=false;
676    bool sawDS=false;
677    bool crossedZoneCut = false;
678    while(B.get(rr)) {
679      if(rr.qtype.getCode() == QType::NS && p->qtype.getCode() != QType::NS) { // possible retargeting
680        relevantNS=true;
681      }
682
683      if(rr.qtype.getCode()==QType::DS && p->qtype.getCode() == QType::NS && p->d_dnssecOk) {
684        sawDS = true;
685        r->addRecord(rr);
686      }
687
688      if(rr.qtype.getCode()!=QType::NS || p->qtype.getCode()==QType::NS)
689        hits++;
690      if(!rfound && rr.qtype.getCode()==QType::CNAME) {
691        found=true;
692        r->addRecord(rr);
693        target=rr.content; // for retargeting
694      }
695      if(shortcut && !found && rr.qtype==p->qtype) {
696        if(!rr.auth) {
697        // no idea why this if is here
698        }
699         
700        rfound=true;
701        r->addRecord(rr);
702      }
703    }
704
705    if(crossedZoneCut) {
706      cerr<<"Should return NS records, and this A/AAAA record in the additional section.."<<endl;
707    }
708
709    if(!sawDS && p->qtype.getCode() == QType::NS && p->d_dnssecOk && rfound) {
710      addNSECX(p, r, p->qdomain, "", 2); // make it 'official' that we have no DS
711    }
712
713    if(hits && !relevantNS && !found && !rfound && shortcut ) { // XXX FIXME !numloops. we found matching qnames but not a qtype
714      DLOG(L<<"Found matching qname, but not the qtype"<<endl);
715      return 2;
716    }
717
718    if(rfound)
719      return 1; // ANY lookup found the right answer immediately
720
721    if(found) {
722      if(p->qtype.getCode()==QType::CNAME) // they really wanted a CNAME!
723        return 1;
724      DLOG(L<<"Looping because of a CNAME to "<<target<<endl);
725      found=false;
726    }
727    else 
728      break;
729  }
730
731  // we now have what we really search for ready in 'target'
732  return 0;
733}
734
735/* Semantics:
736   
737- only one backend owns the SOA of a zone
738- only one AXFR per zone at a time - double startTransaction should fail
739- backends need to implement transaction semantics
740
741
742How BindBackend would implement this:
743   startTransaction makes a file
744   feedRecord sends everything to that file
745   commitTransaction moves that file atomically over the regular file, and triggers a reload
746   rollbackTransaction removes the file
747
748
749How PostgreSQLBackend would implement this:
750   startTransaction starts a sql transaction, which also deletes all records
751   feedRecord is an insert statement
752   commitTransaction commits the transaction
753   rollbackTransaction aborts it
754
755How MySQLBackend would implement this:
756   (good question!)
757   
758*/     
759
760int PacketHandler::trySuperMaster(DNSPacket *p)
761{
762  Resolver::res_t nsset;
763  try {
764    Resolver resolver;
765    uint32_t theirserial;
766    resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial); 
767 
768    resolver.resolve(p->getRemote(),p->qdomain.c_str(), QType::NS);
769
770    nsset=resolver.result();
771  }
772  catch(ResolverException &re) {
773    L<<Logger::Error<<"Error resolving SOA or NS at: "<< p->getRemote() <<": "<<re.reason<<endl;
774    return RCode::ServFail;
775  }
776
777  string account;
778  DNSBackend *db;
779  if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &account, &db)) {
780    L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<endl;
781    return RCode::Refused;
782  }
783  db->createSlaveDomain(p->getRemote(),p->qdomain,account);
784  Communicator.addSuckRequest(p->qdomain, p->getRemote()); 
785  L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<", queued axfr"<<endl;
786  return RCode::NoError;
787}
788
789int PacketHandler::processNotify(DNSPacket *p)
790{
791  /* now what?
792     was this notification from an approved address?
793     We determine our internal SOA id (via UeberBackend)
794     We determine the SOA at our (known) master
795     if master is higher -> do stuff
796  */
797  if(!::arg().mustDo("slave")) {
798    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
799    return RCode::NotImp;
800  }
801  DNSBackend *db=0;
802  DomainInfo di;
803  di.serial = 0;
804  if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
805    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
806    return trySuperMaster(p);
807  }
808   
809  string authServer(p->getRemote());
810  if(::arg().contains("trusted-notification-proxy", p->getRemote())) {
811    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
812    if(di.masters.empty()) {
813      L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
814      return RCode::Refused;
815    }
816
817    authServer = *di.masters.begin();
818
819  }
820  else if(!db->isMaster(p->qdomain, p->getRemote())) {
821    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
822    return RCode::Refused;
823  }
824
825  uint32_t theirserial=0;
826
827  /* to quote Rusty Russell - this code is so bad that you can actually hear it suck */
828  /* this is an instant DoS, just spoof notifications from the address of the master and we block  */
829
830  Resolver resolver;
831  try {
832    resolver.getSoaSerial(authServer, p->qdomain, &theirserial);
833  }
834  catch(ResolverException& re) {
835    L<<Logger::Error<<re.reason<<endl;
836    return RCode::ServFail;
837  }
838
839  if(theirserial<=di.serial) {
840    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<< authServer <<", we are up to date: "<<
841      theirserial<<"<="<<di.serial<<endl;
842    return RCode::NoError;
843  }
844  else {
845    L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<di.id<<") from master "<<p->getRemote()<<": "<<
846      theirserial<<" > "<<di.serial<<endl;
847
848    Communicator.addSuckRequest(p->qdomain, authServer, true); // priority
849  }
850  return -1; 
851}
852
853
854
855bool validDNSName(const string &name)
856{
857  string::size_type pos, length=name.length();
858  char c;
859  for(pos=0; pos < length; ++pos) {
860    c=name[pos];
861    if(!((c >= 'a' && c <= 'z') ||
862         (c >= 'A' && c <= 'Z') ||
863         (c >= '0' && c <= '9') ||
864         c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@'))
865      return false;
866  }
867  return true;
868} 
869
870DNSPacket *PacketHandler::question(DNSPacket *p)
871{
872  bool shouldRecurse=false;
873  DNSPacket *ret=questionOrRecurse(p, &shouldRecurse);
874  if(shouldRecurse) {
875    DP->sendPacket(p);
876  }
877  return ret;
878}
879
880void PacketHandler::synthesiseRRSIGs(DNSPacket* p, DNSPacket* r)
881{
882  cerr<<"Need to fake up the RRSIGs some way.."<<endl;
883  B.lookup(QType(QType::ANY), p->qdomain, p);
884 
885  DNSResourceRecord rr;
886 
887  typedef map<uint16_t, vector<shared_ptr<DNSRecordContent> > > records_t;
888  records_t records;
889
890  NSECRecordContent nrc;
891  nrc.d_set.insert(QType::RRSIG);
892  nrc.d_set.insert(QType::NSEC);
893
894  while(B.get(rr)) {
895    if(!rr.auth) 
896      continue;
897   
898    // this deals with the 'prio' mismatch!
899    if(rr.qtype.getCode()==QType::MX || rr.qtype.getCode() == QType::SRV) { 
900      rr.content = lexical_cast<string>(rr.priority) + " " + rr.content;
901    }
902   
903    if(!rr.content.empty() && rr.qtype.getCode()==QType::TXT && rr.content[0]!='"') {
904      rr.content="\""+rr.content+"\"";
905    }
906    if(rr.content.empty())  // empty contents confuse the MOADNS setup
907      rr.content=".";
908    shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)); 
909   
910    records[rr.qtype.getCode()].push_back(drc);
911    nrc.d_set.insert(rr.qtype.getCode());
912  }
913
914  // now get the fucking NSEC too (since we must sign it!)
915
916  SOAData sd;
917  sd.db=(DNSBackend *)-1; // force uncached answer
918  getAuth(p, &sd, p->qdomain, 0);
919
920  string before,after;
921  sd.db->getBeforeAndAfterNames(sd.domain_id, sd.qname, p->qdomain, before, after); 
922
923  nrc.d_next=after;
924
925  rr.qname=p->qdomain;
926  rr.ttl=3600;
927  rr.qtype=QType::NSEC;
928  rr.content=nrc.getZoneRepresentation();
929
930  records[QType::NSEC].push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
931
932  // ok, the NSEC is in..
933
934  cerr<<"Have "<<records.size()<<" rrsets to sign"<<endl;
935
936  rr.qname = p->qdomain;
937  rr.ttl = 3600;
938  rr.auth = 0; // please don't sign this!
939  rr.d_place = DNSResourceRecord::ANSWER;
940  rr.qtype = QType::RRSIG;
941
942  BOOST_FOREACH(records_t::value_type& iter, records) {
943    RRSIGRecordContent rrc;
944    for(int ksk =0 ; ksk < 2; ++ksk) {
945      getRRSIGForRRSET(d_dk, p->qdomain, iter.first, 3600, iter.second, rrc, ksk);
946      rr.content=rrc.getZoneRepresentation();
947      r->addRecord(rr);
948      if(iter.first != QType::DNSKEY)
949        break;
950    }
951  }
952}
953
954void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd)
955{
956  DNSResourceRecord rr;
957  rr.qname=sd.qname;
958  rr.qtype=QType::SOA;
959  rr.content=serializeSOAData(sd);
960  rr.ttl=sd.ttl;
961  rr.domain_id=sd.domain_id;
962  rr.d_place=DNSResourceRecord::AUTHORITY;
963  rr.auth = 1;
964  r->addRecord(rr);
965 
966  if(p->d_dnssecOk) 
967    addNSECX(p, r, target, sd.qname, 1);
968  r->setRcode(RCode::NXDomain); 
969  S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
970}
971
972void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const std::string& target, SOAData& sd)
973{
974  DNSResourceRecord rr;
975  rr.qname=sd.qname;
976  rr.qtype=QType::SOA;
977  rr.content=serializeSOAData(sd);
978  rr.ttl=sd.ttl;
979  rr.domain_id=sd.domain_id;
980  rr.d_place=DNSResourceRecord::AUTHORITY;
981  rr.auth = 1;
982  r->addRecord(rr);
983 
984  if(p->d_dnssecOk)
985    addNSECX(p, r, target, sd.qname, 0);
986
987  S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
988}
989
990
991bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const string& dsname)
992{
993  B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
994  DNSResourceRecord rr;
995  bool gotOne=false;
996  while(B.get(rr)) {
997    gotOne=true;
998    rr.d_place = DNSResourceRecord::AUTHORITY;
999    r->addRecord(rr);
1000  }
1001  return gotOne;
1002}
1003
1004bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
1005{
1006  vector<DNSResourceRecord> rrset = getBestReferralNS(p, sd, target);
1007  if(rrset.empty())
1008    return false;
1009 
1010  cerr<<"The best NS is: "<<rrset.begin()->qname<<endl;
1011  BOOST_FOREACH(DNSResourceRecord rr, rrset) {
1012    cerr<<"\tadding '"<<rr.content<<"'\n";
1013    rr.d_place=DNSResourceRecord::AUTHORITY;
1014    r->addRecord(rr);
1015  }
1016  r->setA(false);
1017
1018  if(!addDSforNS(p, r, sd, rrset.begin()->qname))
1019    addNSECX(p, r, rrset.begin()->qname, sd.qname, 0);
1020 
1021  return true;
1022}
1023
1024void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
1025{
1026  if(!p->d_dnssecOk)
1027    cerr<<"Need to add all the RRSIGs too for '"<<target<<"', should do this manually since DNSSEC was not requested"<<endl;
1028  //  cerr<<"Need to add all the NSEC too.."<<endl; /// XXX FIXME THE ABOVE IF IS WEIRD
1029  addNSECX(p, r, target, sd.qname, 2); 
1030  if(pdns_iequals(sd.qname, p->qdomain)) {
1031    DNSSECKeeper::keyset_t zskset = d_dk.getKeys(p->qdomain);
1032    DNSResourceRecord rr;
1033    BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, zskset) {
1034      rr.qtype=QType::DNSKEY;
1035      rr.ttl=3600;
1036      rr.qname=p->qdomain;
1037      rr.content=value.first.getDNSKEY().getZoneRepresentation();
1038      rr.auth = true;
1039      r->addRecord(rr);
1040    }
1041  }
1042}
1043
1044bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, string &target, bool& retargeted)
1045{
1046  retargeted=false;
1047
1048  vector<DNSResourceRecord> rrset = getBestWildcard(p, sd, target);
1049  if(rrset.empty())
1050    return false;
1051
1052  cerr<<"The best wildcard match: "<<rrset.begin()->qname<<endl;
1053  BOOST_FOREACH(DNSResourceRecord rr, rrset) {
1054    if(rr.qtype.getCode() == QType::CNAME)  {
1055      retargeted=true;
1056      target=rr.content;
1057    }
1058
1059    rr.wildcardname = rr.qname;
1060    rr.qname=p->qdomain;
1061    cerr<<"\tadding '"<<rr.content<<"'\n";
1062    rr.d_place=DNSResourceRecord::ANSWER;
1063    r->addRecord(rr);
1064  }
1065
1066  if(p->d_dnssecOk) {
1067    addNSECX(p, r, p->qdomain, sd.qname, 3);
1068  }
1069  return true;
1070}
1071
1072
1073//! Called by the Distributor to ask a question. Returns 0 in case of an error
1074DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
1075{
1076  *shouldRecurse=false;
1077  DNSResourceRecord rr;
1078  SOAData sd;
1079  sd.db=0;
1080 
1081  string subdomain="";
1082  string soa;
1083  int retargetcount=0;
1084
1085  vector<DNSResourceRecord> rrset;
1086  bool weDone=0, weRedirected=0, weHaveUnauth=0;
1087
1088  DNSPacket *r=0;
1089  try {   
1090    L << Logger::Notice<<"Remote "<< p->remote.toString() <<" wants a type " << p->qtype.getName() << " ("<<p->qtype.getCode()<<") about '"<<p->qdomain << "'" << endl;
1091
1092    if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1093      L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1094      S.inc("corrupt-packets");
1095      return 0;
1096    }
1097
1098    // XXX FIXME do this in DNSPacket::parse ?
1099
1100    if(!validDNSName(p->qdomain)) {
1101      if(::arg().mustDo("log-dns-details"))
1102        L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
1103      S.inc("corrupt-packets");
1104      r=p->replyPacket(); 
1105      r->setRcode(RCode::ServFail);
1106      return r;
1107    }
1108    if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1109      if(p->d.opcode==Opcode::Update) {
1110        if(::arg().mustDo("log-failed-updates"))
1111          L<<Logger::Notice<<"Received an UPDATE opcode from "<<p->getRemote()<<" for "<<p->qdomain<<", sending NOTIMP"<<endl;
1112        r=p->replyPacket(); 
1113        r->setRcode(RCode::NotImp); // notimp;
1114        return r; 
1115      }
1116      else if(p->d.opcode==Opcode::Notify) {
1117        int res=processNotify(p);
1118        if(res>=0) {
1119          DNSPacket *r=p->replyPacket();
1120          r->setRcode(res);
1121          r->setOpcode(Opcode::Notify);
1122          return r;
1123        }
1124        return 0;
1125      }
1126     
1127      L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1128
1129      r=p->replyPacket(); 
1130      r->setRcode(RCode::NotImp); 
1131      return r; 
1132    }
1133
1134    // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<<endl;
1135   
1136    r=p->replyPacket();  // generate an empty reply packet
1137    if(p->d.rd && d_doRecursion && DP->recurseFor(p))  // make sure we set ra if rd was set, and we'll do it
1138      r->d.ra=true;
1139
1140    if(p->qtype.getCode()==QType::IXFR) {
1141      r->setRcode(RCode::NotImp);
1142      return r;
1143    }
1144
1145    // please don't query fancy records directly!
1146    if(d_doFancyRecords && (p->qtype.getCode()==QType::URL || p->qtype.getCode()==QType::CURL || p->qtype.getCode()==QType::MBOXFW)) {
1147      r->setRcode(RCode::ServFail);
1148      return r;
1149    }
1150   
1151    string target=p->qdomain;
1152    bool noCache=false;
1153
1154    if(doDNSKEYRequest(p,r)) 
1155      goto sendit;
1156
1157    if(doNSEC3PARAMRequest(p,r)) 
1158      goto sendit;
1159
1160    if(doVersionRequest(p,r,target)) // catch version.bind requests
1161      goto sendit;
1162
1163    if(p->qclass==255) // any class query
1164      r->setA(false);
1165    else if(p->qclass != QClass::IN) // we only know about IN, so we don't find anything
1166      goto sendit;
1167
1168  retargeted:;
1169    if(retargetcount > 10) {    // XXX FIXME, retargetcount++?
1170      r->setRcode(RCode::ServFail);
1171      return r;
1172    }
1173   
1174    if(!getAuth(p, &sd, target, 0)) {
1175      r->setA(false);
1176      if(::arg().mustDo("send-root-referral")) {
1177        DLOG(L<<Logger::Warning<<"Adding root-referral"<<endl);
1178        addRootReferral(r);
1179      }
1180      else {
1181        DLOG(L<<Logger::Warning<<"Adding SERVFAIL"<<endl);
1182        r->setRcode(RCode::ServFail);  // 'sorry'
1183      }
1184      goto sendit;
1185    }
1186    DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
1187    // we know we have authority
1188
1189    if(p->qtype.getCode() == QType::SOA && pdns_iequals(sd.qname, p->qdomain)) {
1190        rr.qname=sd.qname;
1191      rr.qtype=QType::SOA;
1192      rr.content=serializeSOAData(sd);
1193      rr.ttl=sd.ttl;
1194      rr.domain_id=sd.domain_id;
1195      rr.d_place=DNSResourceRecord::ANSWER;
1196      rr.auth = true;
1197      r->addRecord(rr);
1198      goto sendit;
1199    }
1200
1201    // this TRUMPS a cname!
1202    if(p->qtype.getCode() == QType::NSEC && p->d_dnssecOk) {
1203      addNSEC(p, r, target, "", 2); // only NSEC please
1204      goto sendit;
1205    }
1206   
1207    // this TRUMPS a cname!
1208    if(p->qtype.getCode() == QType::RRSIG && p->d_dnssecOk) {
1209      synthesiseRRSIGs(p, r);
1210      goto sendit; 
1211    }
1212
1213    // see what we get..
1214    B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1215    rrset.clear();
1216    weDone=weRedirected=weHaveUnauth=0;
1217   
1218    while(B.get(rr)) {
1219      if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) 
1220        weDone=1;
1221      if((rr.qtype == p->qtype || rr.qtype.getCode() == QType::NS) && !rr.auth) 
1222        weHaveUnauth=1;
1223
1224      if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME) 
1225        weRedirected=1;
1226      rrset.push_back(rr);
1227    }
1228
1229    //cerr<<"After first ANY query: weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<endl;
1230
1231    if(rrset.empty()) {
1232      // try wildcards, and if they don't work, go look for NS records
1233      cerr<<"Found nothing in the ANY, but let's try wildcards.."<<endl;
1234      bool wereRetargeted;
1235      if(tryWildcard(p, r, sd, target, wereRetargeted)) {
1236        if(wereRetargeted) {
1237          retargetcount++;
1238          goto retargeted;
1239        }
1240        goto sendit;
1241      }
1242      cerr<<"Found nothing in the ANY and wildcards, let's try NS referral"<<endl;
1243      if(!tryReferral(p, r, sd, target))
1244        makeNXDomain(p, r, target, sd);
1245
1246      goto sendit;
1247    }
1248                                       
1249    if(weRedirected) {
1250      BOOST_FOREACH(rr, rrset) {
1251        if(rr.qtype.getCode() == QType::CNAME) {
1252          r->addRecord(rr);
1253          target = rr.content;
1254          retargetcount++;
1255          goto retargeted;
1256        }
1257      }
1258         
1259    }
1260    else if(weDone) {
1261      BOOST_FOREACH(rr, rrset) {
1262        if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth) 
1263          r->addRecord(rr);
1264      }
1265
1266      if(p->qtype.getCode() == QType::ANY) {
1267        completeANYRecords(p, r, sd, target);
1268      }
1269
1270      goto sendit;
1271    }
1272    else if(weHaveUnauth) {
1273      cerr<<"Have unauth data, so need to hunt for best NS records"<<endl;
1274      if(tryReferral(p, r, sd, target))
1275        goto sendit;
1276      cerr<<"Should not get here!!"<<endl;
1277    }
1278    else {
1279      cerr<<"Have some data, but not the right data"<<endl;
1280      makeNOError(p, r, target, sd);
1281    }
1282   
1283  sendit:;
1284    if(doAdditionalProcessingAndDropAA(p,r)<0)
1285      return 0;
1286
1287    //    doDNSSECProcessing(p, r);
1288
1289    r->wrapup(&d_dk); // needed for inserting in cache
1290    if(!noCache) {
1291      PC.insert(p,r); // in the packet cache
1292    }
1293  }
1294  catch(DBException &e) {
1295    L<<Logger::Error<<"Database module reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
1296    r->setRcode(RCode::ServFail);
1297    S.inc("servfail-packets");
1298    S.ringAccount("servfail-queries",p->qdomain);
1299  }
1300  catch(std::exception &e) {
1301    L<<Logger::Error<<"Exception building answer packet ("<<e.what()<<") sending out servfail"<<endl;
1302    delete r;
1303    r=p->replyPacket();  // generate an empty reply packet   
1304    r->setRcode(RCode::ServFail);
1305    S.inc("servfail-packets");
1306    S.ringAccount("servfail-queries",p->qdomain);
1307  }
1308  return r; 
1309
1310}
1311
Note: See TracBrowser for help on using the browser.