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

Revision 228, 22.3 KB (checked in by ahu, 9 years ago)

b.root
pdns_recursor speedups
mysql support for ports again
valgrind fixes

  • 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  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 as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18*/
19#include "utility.hh"
20#include <string>
21#include <sys/types.h>
22
23#include "dns.hh"
24#include "dnsbackend.hh"
25#include "ueberbackend.hh"
26#include "dnspacket.hh"
27#include "nameserver.hh"
28#include "distributor.hh"
29#include "logger.hh"
30#include "arguments.hh"
31#include "packethandler.hh"
32#include "statbag.hh"
33#include "resolver.hh"
34#include "communicator.hh"
35#include "dnsproxy.hh"
36
37extern StatBag S;
38extern PacketCache PC; 
39extern CommunicatorClass Communicator;
40extern DNSProxy *DP;
41
42int PacketHandler::s_count;
43extern string s_programname;
44
45PacketHandler::PacketHandler():B(s_programname)
46{
47  s_count++;
48  d_doFancyRecords = (arg()["fancy-records"]!="no");
49  d_doWildcards = (arg()["wildcards"]!="no");
50  d_doCNAME = (arg()["skip-cname"]=="no");
51  d_doRecursion= arg().mustDo("recursor");
52  d_logDNSDetails= arg().mustDo("log-dns-details");
53  d_doIPv6AdditionalProcessing = arg().mustDo("do-ipv6-additional-processing");
54}
55
56DNSBackend *PacketHandler::getBackend()
57{
58  return &B;
59}
60
61PacketHandler::~PacketHandler()
62{
63  --s_count;
64  DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
65}
66
67
68int PacketHandler::findMboxFW(DNSPacket *p, DNSPacket *r, string &target)
69{
70  DNSResourceRecord rr;
71  bool wedoforward=false;
72
73  SOAData sd;
74  int zoneId;
75  if(!getAuth(p, &sd, target, &zoneId))
76    return false;
77
78  B.lookup("MBOXFW",string("%@")+target,p, zoneId);
79     
80  while(B.get(rr))
81    wedoforward=true;
82
83  if(wedoforward) {
84    rr.content=arg()["smtpredirector"];
85    rr.priority=25;
86    rr.ttl=7200;
87    rr.qtype=QType::MX;
88    rr.qname=target;
89   
90    r->addRecord(rr);
91  }
92
93  return wedoforward;
94}
95
96int PacketHandler::findUrl(DNSPacket *p, DNSPacket *r, string &target)
97{
98  DNSResourceRecord rr;
99
100  bool found=false;
101     
102  B.lookup("URL",target,p); // search for a URL before we search for an A
103       
104  while(B.get(rr)) {
105    found=true;
106    DLOG(L << "Found a URL!" << endl);
107    rr.content=arg()["urlredirector"];
108    rr.qtype=QType::A; 
109    rr.qname=target;
110         
111    r->addRecord(rr);
112  } 
113
114  if(found)
115    return 1;
116     
117  // now try CURL
118 
119  B.lookup("CURL",target,p); // search for a URL before we search for an A
120     
121  while(B.get(rr)) {
122    found=true;
123    DLOG(L << "Found a CURL!" << endl);
124    rr.content=arg()["urlredirector"];
125    rr.qtype=1; // A
126    rr.qname=target;
127    rr.ttl=300;
128    r->addRecord(rr);
129  } 
130
131  if(found)
132    return found;
133  return 0;
134}
135
136/** Returns 0 if nothing was found, -1 if an error occured or 1 if the search
137    was satisfied */
138int PacketHandler::doFancyRecords(DNSPacket *p, DNSPacket *r, string &target)
139{
140  DNSResourceRecord rr;
141
142  if(p->qtype.getCode()==QType::MX)  // check if this domain has smtp service from us
143    return findMboxFW(p,r,target);
144 
145  if(p->qtype.getCode()==QType::A)   // search for a URL record for an A
146    return findUrl(p,r,target);
147
148  return 0;
149}
150
151int PacketHandler::doDNSCheckRequest(DNSPacket *p, DNSPacket *r, string &target)
152{
153  int result = 0;
154  DNSResourceRecord rr;
155
156  if (p->qclass == 3 && p->qtype.getName() == "HINFO") {
157    rr.content = "PowerDNS $Id: packethandler.cc,v 1.23 2004/02/01 18:20:16 ahu Exp $";
158    rr.ttl = 5;
159    rr.qname=target;
160    rr.qtype=13; // hinfo
161    r->addRecord(rr);
162    result = 1;
163  }
164 
165  return result;
166}
167
168/** This catches version requests. Returns 1 if it was handled, 0 if it wasn't */
169int PacketHandler::doVersionRequest(DNSPacket *p, DNSPacket *r, string &target)
170{
171  DNSResourceRecord rr;
172  if(p->qtype.getCode()==QType::TXT && target=="version.bind") {// TXT
173    rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc,v 1.23 2004/02/01 18:20:16 ahu Exp $";
174    rr.ttl=5;
175    rr.qname=target;
176    rr.qtype=QType::TXT; // TXT
177    r->addRecord(rr);
178   
179    return 1;
180  }
181  return 0;
182}
183
184/** Determines if we are authoritative for a zone, and at what level */
185bool PacketHandler::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
186{
187  string subdomain(target);
188  do {
189    if( B.getSOA( subdomain, *sd ) ) {
190      sd->qname = subdomain;
191      *zoneId = sd->domain_id;
192      return true;
193    }
194  }
195  while( chopOff( subdomain ) );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
196  return false;
197}
198
199/** returns 1 in case of a straight match, 2 in case of a wildcard CNAME (groan), 0 in case of no hit */
200int PacketHandler::doWildcardRecords(DNSPacket *p, DNSPacket *r, string &target)
201{
202  DNSResourceRecord rr;
203  bool found=false, retargeted=false;
204
205  // try chopping off domains and look for wildcard matches
206
207  // *.pietje.nl IN  A 1.2.3.4
208  // pietje.nl should now NOT match, but www.pietje.nl should
209
210  string subdomain=target;
211  string::size_type pos;
212  while((pos=subdomain.find("."))!=string::npos) {
213    subdomain=subdomain.substr(pos+1);
214    // DLOG();
215
216    string searchstr=string("*.")+subdomain;
217
218    B.lookup(QType(QType::ANY), searchstr,p); // start our search at the backend
219
220    while(B.get(rr)) { // read results
221      found=true;
222      if((p->qtype.getCode()==QType::ANY || rr.qtype==p->qtype) || rr.qtype.getCode()==QType::CNAME) {
223        rr.qname=target;
224        r->addRecord(rr);  // and add
225        if(rr.qtype.getCode()==QType::CNAME) {
226          if(target==rr.content) {
227            L<<Logger::Error<<"Ignoring wildcard CNAME '"<<rr.qname<<"' pointing at itself"<<endl;
228            r->setRcode(RCode::ServFail);
229            continue;
230          }
231         
232          DLOG(L<<Logger::Error<<"Retargeting because of wildcard cname, from "<<target<<" to "<<rr.content<<endl);
233         
234          target=rr.content; // retarget
235          retargeted=true;
236        }
237      }
238      else if(d_doFancyRecords && arg().mustDo("wildcard-url") && p->qtype.getCode()==QType::A && rr.qtype.getName()=="URL") {
239        rr.content=arg()["urlredirector"];
240        rr.qtype=QType::A; 
241        rr.qname=target;
242       
243        r->addRecord(rr);
244      }
245    }
246    if(found) {
247      DLOG(L<<"Wildcard match on '"<<string("*.")+subdomain<<"'"<<endl);
248      return retargeted ? 2 : 1;
249    }
250  }
251  return 0;
252}
253
254/** dangling is declared true if we were unable to resolve everything */
255int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r)
256{
257  DNSResourceRecord rr;
258  SOAData sd;
259
260  if(p->qtype.getCode()!=QType::AXFR && r->needAP()) { // this packet needs additional processing
261    DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
262
263    vector<DNSResourceRecord *> arrs=r->getAPRecords();
264    vector<DNSResourceRecord> crrs;
265
266    for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin();
267        i!=arrs.end();  ++i) 
268      crrs.push_back(**i);
269
270    // we now have a copy, push_back on packet might reallocate!
271
272    for(vector<DNSResourceRecord>::const_iterator i=crrs.begin();
273        i!=crrs.end();
274        ++i) {
275     
276      if(i->qtype.getCode()==QType::NS && !B.getSOA(i->qname,sd)) { // drop AA in case of non-SOA-level NS answer
277        r->d.aa=false;
278        //      i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
279      }
280
281      QType qtypes[2];
282      qtypes[0]="A"; qtypes[1]="AAAA";
283      for(int n=0;n < d_doIPv6AdditionalProcessing + 1; ++n) {
284        B.lookup(qtypes[n],i->content,p); 
285        bool foundOne=false;
286        while(B.get(rr)) {
287          foundOne=true;
288          if(rr.domain_id!=i->domain_id && arg()["out-of-zone-additional-processing"]=="no") {
289            DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
290            continue; // not adding out-of-zone additional data
291          }
292         
293          rr.d_place=DNSResourceRecord::ADDITIONAL;
294          r->addRecord(rr);
295         
296        }
297        if(!foundOne) {
298          if(d_doRecursion && DP->recurseFor(p)) {
299            try {
300              Resolver resolver;
301              resolver.resolve(arg()["recursor"],i->content.c_str(),QType::A);
302              Resolver::res_t res=resolver.result();
303              for(Resolver::res_t::const_iterator j=res.begin();j!=res.end();++j) {
304                if(j->d_place==DNSResourceRecord::ANSWER) {
305                  rr=*j;
306                  rr.d_place=DNSResourceRecord::ADDITIONAL;
307                  r->addRecord(rr);
308                }
309              }
310            }
311            catch(ResolverException& re) {
312              // L<<Logger::Error<<"Trying to do additional processing for answer to '"<<p->qdomain<<"' query: "<<re.reason<<endl;
313            }
314          }
315        }
316      }
317    }
318  }
319  return 1;
320}
321
322/* returns 1 if everything is done & ready, 0 if the search should continue */
323int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target)
324{
325  DNSResourceRecord rr;
326
327  bool found=false, rfound=false;
328
329  if(p->qtype.getCode()!=QType::CNAME && !d_doCNAME)
330    return 0;
331
332  // Traverse a CNAME chain if needed
333  for(int numloops=0;;numloops++) {
334    if(numloops==10) {
335      L<<Logger::Error<<"Detected a CNAME loop involving "<<target<<", sending SERVFAIL"<<endl;
336      r->setRcode(2);
337      return 1;
338    }
339
340    B.lookup(QType(QType::ANY),target,p);
341       
342    bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY;
343
344    while(B.get(rr)) {
345      if(!rfound && rr.qtype.getCode()==QType::CNAME) {
346        found=true;
347        r->addRecord(rr);
348        target=rr.content; // for retargeting
349      }
350      if(shortcut && !found && rr.qtype==p->qtype) {
351        rfound=true;
352        r->addRecord(rr);
353      }
354    }
355    if(rfound)
356      return 1; // ANY lookup found the right answer immediately
357
358    if(found) {
359      if(p->qtype.getCode()==QType::CNAME) // they really wanted a CNAME!
360        return 1;
361      DLOG(L<<"Looping because of a CNAME to "<<target<<endl);
362      found=false;
363    }
364    else break;
365  }
366
367  // we now have what we really search for ready in 'target'
368  return 0;
369}
370
371/* Semantics:
372   
373- only one backend owns the SOA of a zone
374- only one AXFR per zone at a time - double startTransaction should fail
375- backends need to implement transaction semantics
376
377
378How BindBackend would implement this:
379   startTransaction makes a file
380   feedRecord sends everything to that file
381   commitTransaction moves that file atomically over the regular file, and triggers a reload
382   rollbackTransaction removes the file
383
384
385How PostgreSQLBackend would implement this:
386   startTransaction starts a sql transaction, which also deletes all records
387   feedRecord is an insert statement
388   commitTransaction commits the transaction
389   rollbackTransaction aborts it
390
391How MySQLBackend would implement this:
392   (good question!)
393   
394*/     
395
396int PacketHandler::trySuperMaster(DNSPacket *p)
397{
398  Resolver::res_t nsset;
399  try {
400    Resolver resolver;
401    u_int32_t theirserial;
402    int res=resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial); 
403    if(res<=0) {
404      L<<Logger::Error<<"Unable to determine SOA serial for "<<p->qdomain<<" at potential supermaster "<<p->getRemote()<<endl;
405      return RCode::ServFail;
406    }
407 
408    resolver.resolve(p->getRemote(),p->qdomain.c_str(), QType::NS);
409
410    nsset=resolver.result();
411  }
412  catch(ResolverException &re) {
413    L<<Logger::Error<<"Error resolving SOA or NS for '"<<p->qdomain<<"' at "<<p->getRemote()<<endl;
414    return RCode::ServFail;
415  }
416
417  string account;
418  DNSBackend *db;
419  if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &account, &db)) {
420   L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<endl;
421    return RCode::Refused;
422  }
423  db->createSlaveDomain(p->getRemote(),p->qdomain,account);
424  Communicator.addSuckRequest(p->qdomain, p->getRemote()); 
425  L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<", queued axfr"<<endl;
426  return RCode::NoError;
427}
428
429int PacketHandler::doNotify(DNSPacket *p)
430{
431  /* now what?
432     was this notification from an approved address?
433     We determine our internal SOA id (via UeberBackend)
434     We determine the SOA at our (known) master
435     if master is higher -> do stuff
436  */
437  if(!arg().mustDo("slave")) {
438    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
439    return RCode::NotImp;
440  }
441  DNSBackend *db=0;
442  DomainInfo di;
443  if(!B.getDomainInfo(p->qdomain,di) || !(db=di.backend)) {
444    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
445    return trySuperMaster(p);
446  }
447   
448  if(!db->isMaster(p->qdomain, p->getRemote())) {
449    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
450    return RCode::Refused;
451  }
452
453  u_int32_t theirserial=0;
454
455  /* to quote Rusty Russell - this code is so bad that you can actually hear it suck */
456  /* this is an instant DoS, just spoof notifications from the address of the master and we block  */
457
458  Resolver resolver;
459  int res=resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial);
460  if(res<=0) {
461    L<<Logger::Error<<"Unable to determine SOA serial for "<<p->qdomain<<" at "<<p->getRemote()<<endl;
462    return RCode::ServFail;
463  }
464       
465
466  if(theirserial<=di.serial) {
467    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from master "<<p->getRemote()<<", we are up to date: "<<
468      theirserial<<"<="<<di.serial<<endl;
469    return RCode::NoError;
470  }
471  else {
472    L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<di.id<<") from master "<<p->getRemote()<<": "<<
473      theirserial<<" > "<<di.serial<<endl;
474
475    Communicator.addSuckRequest(p->qdomain, p->getRemote(),true); // priority
476  }
477  return -1; 
478}
479
480
481//! Called by the Distributor to ask a question. Returns 0 in case of an error
482DNSPacket *PacketHandler::question(DNSPacket *p)
483{
484  DNSResourceRecord rr;
485  SOAData sd;
486  sd.db=0;
487 
488  string subdomain="";
489  string soa;
490  int retargetcount=0;
491  bool noSameLevelNS;
492
493  DNSPacket *r=0;
494  try {   
495    DLOG(L << Logger::Notice<<"Remote "<<inet_ntoa( reinterpret_cast< struct sockaddr_in * >( &( p->remote ))->sin_addr )<<" wants a type " << p->qtype.getName() << " ("<<p->qtype.getCode()<<") about '"<<p->qdomain << "'" << endl);
496
497// XXX FIXME Find out why this isn't working!
498#ifndef WIN32
499    if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
500      L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
501      S.inc("corrupt-packets");
502      return 0;
503    }
504#endif // WIN32
505
506    // XXX FIXME do this in DNSPacket::parse ?
507
508    if(!p->qdomain.empty() && (p->qdomain[0]=='%' || p->qdomain.find('|')!=string::npos) ) {
509      L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': dropping"<<endl;
510      S.inc("corrupt-packets");
511      return 0;
512    }
513    if(p->d.opcode) { // non-zero opcode (again thanks RA!)
514      if(p->d.opcode==Opcode::Update) {
515        if(arg().mustDo("log-failed-updates"))
516          L<<Logger::Notice<<"Received an UPDATE opcode from "<<p->getRemote()<<" for "<<p->qdomain<<", sending NOTIMP"<<endl;
517        r=p->replyPacket(); 
518        r->setRcode(RCode::NotImp); // notimp;
519        return r; 
520      }
521      else if(p->d.opcode==Opcode::Notify) {
522        int res=doNotify(p);
523        if(res>=0) {
524          DNSPacket *r=p->replyPacket();
525          r->setRcode(res);
526          return r;
527        }
528        return 0;
529      }
530     
531      L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
532
533      r=p->replyPacket(); 
534      r->setRcode(RCode::NotImp); 
535      return r; 
536    }
537   
538    r=p->replyPacket();  // generate an empty reply packet
539
540    if(p->qtype.getCode()==QType::IXFR) {
541      r->setRcode(RCode::NotImp);
542      return r;
543    }
544
545    bool found=false;
546   
547    string target=p->qdomain;
548   
549    if (doDNSCheckRequest(p, r, target))
550      goto sendit;
551   
552    if(doVersionRequest(p,r,target)) // catch version.bind requests
553      goto sendit;
554
555    if(p->qclass==255) // any class query
556      r->setA(false);
557    else if(p->qclass!=1) // we only know about IN, so we don't find anything
558      goto sendit;
559
560  retargeted:;
561    if(retargetcount++>10) {
562      L<<Logger::Error<<"Detected wildcard CNAME loop involving '"<<target<<"'"<<endl;
563      r->setRcode(RCode::ServFail);
564      goto sendit;
565    }
566
567    if(makeCanonic(p,r,target)>0) // traverse CNAME chain until we have a useful record (may actually give the correct answer!)
568      goto sendit; // this might be the end of it (client requested a CNAME, or we found the answer already)
569   
570    if(d_doFancyRecords) { // MBOXFW, URL <- fake records, emulated with MX and A
571      int res=doFancyRecords(p,r,target);
572      if(res) { // had a result
573        if(res<0) // it was an error
574          r->setRcode(RCode::ServFail);
575        goto sendit; 
576      }
577    }
578   
579    // now ready to start the real direct search
580
581    if(p->qtype.getCode()==QType::SOA || p->qtype.getCode()==QType::ANY) { // this is special
582
583      if(B.getSOA(target,sd)) {
584        rr.qname=target;
585        rr.qtype=QType::SOA;
586        rr.content=DNSPacket::serializeSOAData(sd);
587        rr.ttl=sd.ttl;
588        rr.domain_id=sd.domain_id;
589        rr.d_place=DNSResourceRecord::ANSWER;
590        r->addRecord(rr);
591        if(p->qtype.getCode()==QType::SOA) { // we are done
592          goto sendit;
593        }
594      }
595    }
596
597    noSameLevelNS=true;
598
599    if(p->qtype.getCode()!=QType::SOA) { // regular direct lookup
600      B.lookup(QType(QType::ANY), target,p);
601     
602      while(B.get(rr)) {
603        if(rr.qtype.getCode()==QType::SOA) // skip any direct SOA responses as they may be different
604          continue;
605        if(rr.qtype==p->qtype || p->qtype.getCode()==QType::ANY ) {
606          DLOG(L<<"Found a direct answer: "<<rr.content<<endl);
607          found=true;
608          r->addRecord(rr);  // and add
609        }
610        else
611          if(rr.qtype.getCode()==QType::NS)
612            noSameLevelNS=false;
613      }
614     
615      if(p->qtype.getCode()==QType::ANY) {
616        if(d_doFancyRecords) { 
617          int res=findMboxFW(p,r,target);
618          if(res<0)
619            L<<Logger::Error<<"Error finding a mailbox record after an ANY query"<<endl;
620          if(res>0) {
621            DLOG(L<<Logger::Error<<"Frobbed an MX in!"<<endl);
622            found=true;
623          }
624        }
625      }
626      if(found) 
627        goto sendit;
628     
629    }
630   
631    // not found yet, try wildcards (we only try here in case of recursion - we should check before we hand off)
632
633    if(p->d.rd && d_doRecursion && d_doWildcards) { 
634      int res=doWildcardRecords(p,r,target);
635      if(res) { // had a result
636        // FIXME: wildCard may retarget us in the future
637        if(res==1)  // had a straight result
638          goto sendit; 
639        if(res==2)
640          goto retargeted;
641        goto sendit; 
642      }
643    }
644
645    // RECURSION CUT-OUT!
646
647
648    bool weAuth;
649    int zoneId;
650    zoneId=-1;
651   
652    if(p->d.rd && d_doRecursion && arg().mustDo("allow-recursion-override"))
653      weAuth=getAuth(p, &sd, target, &zoneId);
654    else
655      weAuth=false;
656
657    if(p->d.rd && d_doRecursion && !weAuth && DP->sendPacket(p)) {
658      delete r;
659      return 0;
660    }
661
662    string::size_type pos;
663   
664    DLOG(L<<"Nothing found so far for '"<<target<<"', do we even have authority over this domain?"<<endl);
665
666    if(zoneId==-1)
667      weAuth=getAuth(p, &sd, target, &zoneId); // TLDAuth perhaps
668
669    if(weAuth) {
670      DLOG(L<<Logger::Warning<<"Soa found: "<<soa<<endl);
671      ;
672    }
673    if(!weAuth) {
674      if(p->d.rd || target==p->qdomain) { // only servfail if we didn't follow a CNAME
675        if(d_logDNSDetails)
676          L<<Logger::Warning<<"Not authoritative for '"<< target<<"', sending servfail to "<<
677            p->getRemote()<< (p->d.rd ? " (recursion was desired)" : "") <<endl;
678
679        r->setA(false);
680        r->setRcode(RCode::ServFail);  // 'sorry' - this is where we might send out a root referral
681      }
682                                       
683      S.ringAccount("unauth-queries",p->qdomain+"/"+p->qtype.getName());
684      S.ringAccount("remotes-unauth",p->getRemote());
685    }
686    else {
687      DLOG(L<<Logger::Warning<<"We ARE authoritative for a subdomain of '"<<target<<"' ("<<sd.qname<<"), perhaps we have a suitable NS record then"<<endl);
688      subdomain=target;
689      found=0;
690      pos=0; 
691     
692      do {
693        if(pos) // skip dot
694          pos++;
695       
696        subdomain=subdomain.substr(pos);
697        if(noSameLevelNS) { // skip first lookup if it is known not to exist
698          noSameLevelNS=false;
699          continue;
700        }
701         
702        if(!Utility::strcasecmp(subdomain.c_str(),sd.qname.c_str())) // about to break out of our zone
703          break; 
704
705        B.lookup("NS", subdomain,p,zoneId);  // start our search at the backend
706       
707        while(B.get(rr)) {
708          found=true;
709          rr.d_place=DNSResourceRecord::AUTHORITY; // this for the authority section
710          r->addRecord(rr);
711        }
712        if(found || (!subdomain.empty() && subdomain[0]=='.')) {  // this catches '..'
713          r->setA(false);  // send out an NS referral, which should be unauth
714          break;
715        }
716      }while((pos=subdomain.find("."))!=string::npos);
717     
718      if(!found) {
719        // try wildcards then
720        if(d_doWildcards) { 
721          int res=doWildcardRecords(p,r,target);
722
723          if(res==1)  // had a straight result
724            goto sendit; 
725          if(res==2)
726            goto retargeted;
727        }
728
729        // we have authority but no answer, so we add the SOA for negative caching
730        rr.qname=sd.qname;
731        rr.qtype=QType::SOA;
732        rr.content=DNSPacket::serializeSOAData(sd);
733        rr.ttl=sd.ttl;
734        rr.domain_id=sd.domain_id;
735        rr.d_place=DNSResourceRecord::AUTHORITY;
736        r->addRecord(rr);
737
738
739        // need to send NXDOMAIN if there are 0 records for whatever type for target
740       
741        B.lookup("ANY",target,p);
742        while(B.get(rr))
743          found=true;
744       
745        if(!found) {
746          SOAData sd2;
747          if(B.getSOA(target,sd2)) // is there a SOA perhaps? (which may not appear in an ANY query)
748            found=true;
749        }
750
751        if(!found) { 
752          if(d_logDNSDetails)
753            L<<Logger::Notice<<"Authoritative NXDOMAIN to "<< p->getRemote() <<" for '"<<target<<"' ("<<p->qtype.getName()<<")"<<endl;
754
755          r->setRcode(RCode::NXDomain); 
756          S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
757        }
758        else {
759          if(d_logDNSDetails)
760            L<<Logger::Notice<<"Authoritative empty NO ERROR to "<< p->getRemote() <<" for '"<<target<<"' ("<<p->qtype.getName()<<"), other types do exist"<<endl;
761          S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
762        }
763      }
764    }
765   
766    // whatever we've built so far, do additional processing
767   
768  sendit:;
769
770    if(doAdditionalProcessingAndDropAA(p,r)<0)
771      return 0;
772   
773
774   
775   
776
777    r->wrapup(); // needed for inserting in cache
778    PC.insert(p,r); // in the packet cache
779  }
780  catch(DBException &e) {
781    L<<Logger::Error<<"Database module reported condition which prevented lookup - sending out servfail"<<endl;
782    r->setRcode(RCode::ServFail);
783    S.inc("servfail-packets");
784    S.ringAccount("servfail-queries",p->qdomain);
785  }
786  return r; 
787
788}
789
Note: See TracBrowser for help on using the browser.