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

Revision 2190, 41.9 KB (checked in by ahu, 2 years ago)

fix crash reported by Marc Laros when using a non-DNSSEC capable backend. Should also improve non-DNSSEC performance.

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