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

Revision 1880, 39.8 KB (checked in by ahu, 2 years ago)

make packetcache further aware of difference between tcp and udp, so we don't serve truncated packets over tcp

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