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

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

if I understand things correctly, powerdns does 'opt-out' NSEC3, but we did not say that in the NSEC3/NSEC3PARAM.
I hope I got it right ;-)

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