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

Revision 161, 22.6 KB (checked in by ahu, 10 years ago)

logging fixes
webserver timeout 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.12 2003/03/17 13:44:53 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.12 2003/03/17 13:44:53 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::getTLDAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
186{
187  static string theSOA="."+arg()["only-soa"];
188  static SOAData cachedSD;
189  static bool haveIt;
190
191  if((target.size()-toLower(target).rfind(toLower(theSOA)))!=theSOA.size()) {
192    //    cerr<<"target '"<<target<<"' does not end on '"<<theSOA<<"'"<<endl;
193    return false;
194  }
195  if(!haveIt) {
196    if(B.getSOA(arg()["only-soa"], cachedSD)) {
197      cachedSD.qname=arg()["only-soa"];
198
199      haveIt=true;
200    }
201  }
202  if(haveIt) {
203    *zoneId=sd->domain_id; 
204    *sd=cachedSD;
205  }
206  return haveIt;
207}
208
209/** Determines if we are authoritative for a zone, and at what level */
210bool PacketHandler::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
211{
212  DNSResourceRecord rr;
213
214  vector<string>parts;
215  stringtok(parts,target,".");  // www.us.powerdns.com -> 'www' 'us' 'powerdns' 'com'
216 
217  unsigned int spos=0;
218  string subdomain;
219  // easy FIXME: convert this to chopOff
220  while(spos<=parts.size()) {
221    if(spos<parts.size()) { // www.us.powerdns.com -> us.powerdns.com -> powerdns.com -> com ->
222      subdomain=parts[spos++];
223      for(unsigned int i=spos;i<parts.size();++i) {
224        subdomain+=".";
225        subdomain+=parts[i];
226      }
227    }
228    else {
229      subdomain=""; // ROOT!
230      spos++;
231    }
232    if(B.getSOA(subdomain, *sd)) {
233      sd->qname=subdomain;
234      *zoneId=sd->domain_id;
235      return true;
236    }
237  }
238
239  return false;
240}
241
242/** returns 1 in case of a straight match, 2 in case of a wildcard CNAME (groan), 0 in case of no hit */
243int PacketHandler::doWildcardRecords(DNSPacket *p, DNSPacket *r, string &target)
244{
245  DNSResourceRecord rr;
246  bool found=false, retargeted=false;
247
248  // try chopping off domains and look for wildcard matches
249
250  // *.pietje.nl IN  A 1.2.3.4
251  // pietje.nl should now NOT match, but www.pietje.nl should
252
253  string subdomain=target;
254  unsigned int pos;
255  while((pos=subdomain.find("."))!=string::npos) {
256    subdomain=subdomain.substr(pos+1);
257    // DLOG();
258
259    string searchstr=string("*.")+subdomain;
260
261    B.lookup(QType(QType::ANY), searchstr,p); // start our search at the backend
262
263    while(B.get(rr)) { // read results
264      found=true;
265      if((p->qtype.getCode()==QType::ANY || rr.qtype==p->qtype) || rr.qtype.getCode()==QType::CNAME) {
266        rr.qname=target;
267        r->addRecord(rr);  // and add
268        if(rr.qtype.getCode()==QType::CNAME) {
269          if(target==rr.content) {
270            L<<Logger::Error<<"Ignoring wildcard CNAME '"<<rr.qname<<"' pointing at itself"<<endl;
271            r->setRcode(RCode::ServFail);
272            continue;
273          }
274         
275          DLOG(L<<Logger::Error<<"Retargeting because of wildcard cname, from "<<target<<" to "<<rr.content<<endl);
276         
277          target=rr.content; // retarget
278          retargeted=true;
279        }
280      }
281      else if(d_doFancyRecords && arg().mustDo("wildcard-url") && p->qtype.getCode()==QType::A && rr.qtype.getName()=="URL") {
282        rr.content=arg()["urlredirector"];
283        rr.qtype=QType::A; 
284        rr.qname=target;
285       
286        r->addRecord(rr);
287      }
288    }
289    if(found) {
290      DLOG(L<<"Wildcard match on '"<<string("*.")+subdomain<<"'"<<endl);
291      return retargeted ? 2 : 1;
292    }
293  }
294  return 0;
295}
296
297/** dangling is declared true if we were unable to resolve everything */
298int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r)
299{
300  DNSResourceRecord rr;
301  SOAData sd;
302
303  if(p->qtype.getCode()!=QType::AXFR && r->needAP()) { // this packet needs additional processing
304    DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
305
306    vector<DNSResourceRecord> arrs=r->getAPRecords();
307    for(vector<DNSResourceRecord>::const_iterator i=arrs.begin();
308        i!=arrs.end();
309        ++i) {
310     
311      if(r->d.aa && i->qtype.getCode()==QType::NS && !B.getSOA(i->qname,sd)) // drop AA in case of non-SOA-level NS answer
312        r->d.aa=false;
313
314      QType qtypes[2];
315      qtypes[0]="A"; qtypes[1]="AAAA";
316      for(int n=0;n < d_doIPv6AdditionalProcessing + 1; ++n) {
317        B.lookup(qtypes[n],i->content,p); 
318        bool foundOne=false;
319        while(B.get(rr)) {
320          foundOne=true;
321          if(rr.domain_id!=i->domain_id && arg()["out-of-zone-additional-processing"]=="no") {
322            DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
323            continue; // not adding out-of-zone additional data
324          }
325         
326          rr.d_place=DNSResourceRecord::ADDITIONAL;
327          r->addRecord(rr);
328         
329        }
330        if(!foundOne) {
331          if(d_doRecursion && DP->recurseFor(p)) {
332            try {
333              Resolver resolver;
334              resolver.resolve(arg()["recursor"],i->content.c_str(),QType::A);
335              Resolver::res_t res=resolver.result();
336              for(Resolver::res_t::const_iterator j=res.begin();j!=res.end();++j) {
337                if(j->d_place==DNSResourceRecord::ANSWER) {
338                  rr=*j;
339                  rr.d_place=DNSResourceRecord::ADDITIONAL;
340                  r->addRecord(rr);
341                }
342              }
343            }
344            catch(ResolverException& re) {
345              // L<<Logger::Error<<"Trying to do additional processing for answer to '"<<p->qdomain<<"' query: "<<re.reason<<endl;
346            }
347          }
348        }
349      }
350    }
351  }
352  return 1;
353}
354
355/* returns 1 if everything is done & ready, 0 if the search should continue */
356int PacketHandler::makeCanonic(DNSPacket *p, DNSPacket *r, string &target)
357{
358  DNSResourceRecord rr;
359
360  bool found=false, rfound=false;
361
362  if(p->qtype.getCode()!=QType::CNAME && !d_doCNAME)
363    return 0;
364
365  // Traverse a CNAME chain if needed
366  for(int numloops=0;;numloops++) {
367    if(numloops==10) {
368      L<<Logger::Error<<"Detected a CNAME loop involving "<<target<<", sending SERVFAIL"<<endl;
369      r->setRcode(2);
370      return 1;
371    }
372
373    B.lookup(QType(QType::ANY),target,p);
374       
375    bool shortcut=p->qtype.getCode()!=QType::SOA && p->qtype.getCode()!=QType::ANY;
376
377    while(B.get(rr)) {
378      if(!rfound && rr.qtype.getCode()==QType::CNAME) {
379        found=true;
380        r->addRecord(rr);
381        target=rr.content; // for retargeting
382      }
383      if(shortcut && !found && rr.qtype==p->qtype) {
384        rfound=true;
385        r->addRecord(rr);
386      }
387    }
388    if(rfound)
389      return 1; // ANY lookup found the right answer immediately
390
391    if(found) {
392      if(p->qtype.getCode()==QType::CNAME) // they really wanted a CNAME!
393        return 1;
394      DLOG(L<<"Looping because of a CNAME to "<<target<<endl);
395      found=false;
396    }
397    else break;
398  }
399
400  // we now have what we really search for ready in 'target'
401  return 0;
402}
403
404/* Semantics:
405   
406- only one backend owns the SOA of a zone
407- only one AXFR per zone at a time - double startTransaction should fail
408- backends need to implement transaction semantics
409
410
411How BindBackend would implement this:
412   startTransaction makes a file
413   feedRecord sends everything to that file
414   commitTransaction moves that file atomically over the regular file, and triggers a reload
415   rollbackTransaction removes the file
416
417
418How PostgreSQLBackend would implement this:
419   startTransaction starts a sql transaction, which also deletes all records
420   feedRecord is an insert statement
421   commitTransaction commits the transaction
422   rollbackTransaction aborts it
423
424How MySQLBackend would implement this:
425   (good question!)
426   
427*/     
428
429int PacketHandler::trySuperMaster(DNSPacket *p)
430{
431  Resolver::res_t nsset;
432  try {
433    Resolver resolver;
434    u_int32_t theirserial;
435    int res=resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial); 
436    if(res<=0) {
437      L<<Logger::Error<<"Unable to determine SOA serial for "<<p->qdomain<<" at potential supermaster "<<p->getRemote()<<endl;
438      return RCode::ServFail;
439    }
440 
441    resolver.resolve(p->getRemote(),p->qdomain.c_str(), QType::NS);
442
443    nsset=resolver.result();
444  }
445  catch(ResolverException &re) {
446    L<<Logger::Error<<"Error resolving SOA or NS for '"<<p->qdomain<<"' at "<<p->getRemote()<<endl;
447    return RCode::ServFail;
448  }
449
450  string account;
451  DNSBackend *db;
452  if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &account, &db)) {
453   L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<endl;
454    return RCode::Refused;
455  }
456  db->createSlaveDomain(p->getRemote(),p->qdomain,account);
457  Communicator.addSuckRequest(p->qdomain, p->getRemote()); 
458  L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<", queued axfr"<<endl;
459  return RCode::NoError;
460}
461
462int PacketHandler::doNotify(DNSPacket *p)
463{
464  /* now what?
465     was this notification from an approved address?
466     We determine our internal SOA id (via UeberBackend)
467     We determine the SOA at our (known) master
468     if master is higher -> do stuff
469  */
470  if(!arg().mustDo("slave")) {
471    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
472    return RCode::NotImp;
473  }
474  DNSBackend *db=0;
475  DomainInfo di;
476  if(!B.getDomainInfo(p->qdomain,di) || !(db=di.backend)) {
477    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
478    return trySuperMaster(p);
479  }
480   
481  if(!db->isMaster(p->qdomain, p->getRemote())) {
482    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
483    return RCode::Refused;
484  }
485
486  u_int32_t theirserial=0;
487
488  Resolver resolver;
489  int res=resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial);
490  if(res<=0) {
491    L<<Logger::Error<<"Unable to determine SOA serial for "<<p->qdomain<<" at "<<p->getRemote()<<endl;
492    return RCode::ServFail;
493  }
494       
495
496  if(theirserial<=di.serial) {
497    L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from master "<<p->getRemote()<<", we are up to date: "<<
498      theirserial<<"<="<<di.serial<<endl;
499    return RCode::NoError;
500  }
501  else {
502    L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<di.id<<") from master "<<p->getRemote()<<": "<<
503      theirserial<<" > "<<di.serial<<endl;
504
505    Communicator.addSuckRequest(p->qdomain, p->getRemote());
506  }
507  return -1; 
508}
509
510
511//! Called by the Distributor to ask a question. Returns 0 in case of an error
512DNSPacket *PacketHandler::question(DNSPacket *p)
513{
514  DNSResourceRecord rr;
515  SOAData sd;
516 
517  string subdomain="";
518  string soa;
519  int retargetcount=0;
520  bool noSameLevelNS;
521
522  DNSPacket *r=0;
523  try {   
524    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);
525
526// XXX FIXME Find out why this isn't working!
527#ifndef WIN32
528    if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
529      L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
530      S.inc("corrupt-packets");
531      return 0;
532    }
533#endif // WIN32
534
535    // XXX FIXME do this in DNSPacket::parse ?
536
537    if(!p->qdomain.empty() && (p->qdomain[0]=='%' || p->qdomain.find('|')!=string::npos) ) {
538      L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': dropping"<<endl;
539      S.inc("corrupt-packets");
540      return 0;
541    }
542    if(p->d.opcode) { // non-zero opcode (again thanks RA!)
543      if(p->d.opcode==Opcode::Update) {
544        if(arg().mustDo("log-failed-updates"))
545          L<<Logger::Notice<<"Received an UPDATE opcode from "<<p->getRemote()<<" for "<<p->qdomain<<", sending NOTIMP"<<endl;
546        r=p->replyPacket(); 
547        r->setRcode(RCode::NotImp); // notimp;
548        return r; 
549      }
550      else if(p->d.opcode==Opcode::Notify) {
551        int res=doNotify(p);
552        if(res>=0) {
553          DNSPacket *r=p->replyPacket();
554          r->setRcode(res);
555          return r;
556        }
557        return 0;
558      }
559     
560      L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
561
562      r=p->replyPacket(); 
563      r->setRcode(RCode::NotImp); 
564      return r; 
565    }
566   
567    r=p->replyPacket();  // generate an empty reply packet
568    bool found=false;
569   
570    string target=p->qdomain;
571   
572    if (doDNSCheckRequest(p, r, target))
573      goto sendit;
574   
575    if(doVersionRequest(p,r,target)) // catch version.bind requests
576      goto sendit;
577
578    if(p->qclass==255) // any class query
579      r->setA(false);
580    else if(p->qclass!=1) // we only know about IN, so we don't find anything
581      goto sendit;
582
583  retargeted:;
584    if(retargetcount++>10) {
585      L<<Logger::Error<<"Detected wildcard CNAME loop involving '"<<target<<"'"<<endl;
586      r->setRcode(RCode::ServFail);
587      goto sendit;
588    }
589
590    if(makeCanonic(p,r,target)>0) // traverse CNAME chain until we have a useful record (may actually give the correct answer!)
591      goto sendit; // this might be the end of it (client requested a CNAME, or we found the answer already)
592   
593    if(d_doFancyRecords) { // MBOXFW, URL <- fake records, emulated with MX and A
594      int res=doFancyRecords(p,r,target);
595      if(res) { // had a result
596        if(res<0) // it was an error
597          r->setRcode(RCode::ServFail);
598        goto sendit; 
599      }
600    }
601   
602    // now ready to start the real direct search
603
604    if(p->qtype.getCode()==QType::SOA || p->qtype.getCode()==QType::ANY) { // this is special
605
606      if(B.getSOA(target,sd)) {
607        rr.qname=target;
608        rr.qtype=QType::SOA;
609        rr.content=DNSPacket::serializeSOAData(sd);
610        rr.ttl=sd.ttl;
611        rr.domain_id=sd.domain_id;
612        rr.d_place=DNSResourceRecord::ANSWER;
613        r->addRecord(rr);
614        if(p->qtype.getCode()==QType::SOA) { // we are done
615          goto sendit;
616        }
617      }
618    }
619
620    noSameLevelNS=true;
621
622    if(p->qtype.getCode()!=QType::SOA) { // regular direct lookup
623      B.lookup(QType(QType::ANY), target,p);
624     
625      while(B.get(rr)) {
626        if(rr.qtype.getCode()==QType::SOA) // skip any direct SOA responses as they may be different
627          continue;
628        if(rr.qtype==p->qtype || p->qtype.getCode()==QType::ANY ) {
629          DLOG(L<<"Found a direct answer: "<<rr.content<<endl);
630          found=true;
631          r->addRecord(rr);  // and add
632        }
633        else
634          if(rr.qtype.getCode()==QType::NS)
635            noSameLevelNS=false;
636      }
637     
638      if(p->qtype.getCode()==QType::ANY) {
639        if(d_doFancyRecords) { 
640          int res=findMboxFW(p,r,target);
641          if(res<0)
642            L<<Logger::Error<<"Error finding a mailbox record after an ANY query"<<endl;
643          if(res>0) {
644            DLOG(L<<Logger::Error<<"Frobbed an MX in!"<<endl);
645            found=true;
646          }
647        }
648      }
649      if(found) 
650        goto sendit;
651     
652    }
653   
654    // not found yet, try wildcards (we only try here in case of recursion - we should check before we hand off)
655
656    if(p->d.rd && d_doRecursion && d_doWildcards) { 
657      int res=doWildcardRecords(p,r,target);
658      if(res) { // had a result
659        // FIXME: wildCard may retarget us in the future
660        if(res==1)  // had a straight result
661          goto sendit; 
662        if(res==2)
663          goto retargeted;
664        goto sendit; 
665      }
666    }
667
668    // RECURSION CUT-OUT!
669
670    if(p->d.rd && d_doRecursion && DP->sendPacket(p)) {
671      delete r;
672      return 0;
673    }
674
675    unsigned int pos;
676   
677    DLOG(L<<"Nothing found so far for '"<<target<<"', do we even have authority over this domain?"<<endl);
678   
679    bool weAuth;
680    int zoneId;
681
682    weAuth=getAuth(p, &sd, target, &zoneId); // TLDAuth perhaps
683    if(weAuth) {
684      DLOG(L<<Logger::Warning<<"Soa found: "<<soa<<endl);
685      ;
686    }
687    if(!weAuth) {
688      if(p->d.rd || target==p->qdomain) { // only servfail if we didn't follow a CNAME
689        if(d_logDNSDetails)
690          L<<Logger::Warning<<"Not authoritative for '"<< target<<"', sending servfail to "<<
691            p->getRemote()<< (p->d.rd ? " (recursion was desired)" : "") <<endl;
692
693        r->setA(false);
694        r->setRcode(RCode::ServFail);  // 'sorry' - this is where we might send out a root referral
695      }
696                                       
697      S.ringAccount("unauth-queries",p->qdomain+"/"+p->qtype.getName());
698      S.ringAccount("remotes-unauth",p->getRemote());
699    }
700    else {
701      DLOG(L<<Logger::Warning<<"We ARE authoritative for a subdomain of '"<<target<<"' ("<<sd.qname<<"), perhaps we have a suitable NS record then"<<endl);
702      subdomain=target;
703      found=0;
704      pos=0; 
705     
706      do {
707        if(pos) // skip dot
708          pos++;
709       
710        subdomain=subdomain.substr(pos);
711        if(noSameLevelNS) { // skip first lookup if it is known not to exist
712          noSameLevelNS=false;
713          continue;
714        }
715         
716        if(!Utility::strcasecmp(subdomain.c_str(),sd.qname.c_str())) // about to break out of our zone
717          break; 
718
719        B.lookup("NS", subdomain,p,zoneId);  // start our search at the backend
720       
721        while(B.get(rr)) {
722          found=true;
723          rr.d_place=DNSResourceRecord::AUTHORITY; // this for the authority section
724          r->addRecord(rr);
725        }
726        if(found || (!subdomain.empty() && subdomain[0]=='.')) {  // this catches '..'
727          r->setA(false);  // send out an NS referral, which should be unauth
728          break;
729        }
730      }while((pos=subdomain.find("."))!=string::npos);
731     
732      if(!found) {
733        // try wildcards then
734        if(d_doWildcards) { 
735          int res=doWildcardRecords(p,r,target);
736
737          if(res==1)  // had a straight result
738            goto sendit; 
739          if(res==2)
740            goto retargeted;
741        }
742
743        // we have authority but no answer, so we add the SOA for negative caching
744        rr.qname=sd.qname;
745        rr.qtype=QType::SOA;
746        rr.content=DNSPacket::serializeSOAData(sd);
747        rr.ttl=sd.ttl;
748        rr.domain_id=sd.domain_id;
749        rr.d_place=DNSResourceRecord::AUTHORITY;
750        r->addRecord(rr);
751
752
753        // need to send NXDOMAIN if there are 0 records for whatever type for target
754       
755        B.lookup("ANY",target,p);
756        while(B.get(rr))
757          found=true;
758       
759        if(!found) {
760          SOAData sd2;
761          if(B.getSOA(target,sd2)) // is there a SOA perhaps? (which may not appear in an ANY query)
762            found=true;
763        }
764
765        if(!found) { 
766          if(d_logDNSDetails)
767            L<<Logger::Notice<<"Authoritative NXDOMAIN to "<< p->getRemote() <<" for '"<<target<<"' ("<<p->qtype.getName()<<")"<<endl;
768
769          r->setRcode(RCode::NXDomain); 
770          S.ringAccount("nxdomain-queries",p->qdomain+"/"+p->qtype.getName());
771        }
772        else {
773          if(d_logDNSDetails)
774            L<<Logger::Notice<<"Authoritative empty NO ERROR to "<< p->getRemote() <<" for '"<<target<<"' ("<<p->qtype.getName()<<"), other types do exist"<<endl;
775          S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
776        }
777      }
778    }
779   
780    // whatever we've built so far, do additional processing
781   
782  sendit:;
783
784    if(doAdditionalProcessingAndDropAA(p,r)<0)
785      return 0;
786   
787
788    r->wrapup(); // needed for inserting in cache
789    PC.insert(p,r); // in the packet cache
790  }
791  catch(DBException &e) {
792    L<<Logger::Error<<"Database module reported condition which prevented lookup - sending out servfail"<<endl;
793    r->setRcode(RCode::ServFail);
794    S.inc("servfail-packets");
795    S.ringAccount("servfail-queries",p->qdomain);
796  }
797  return r; 
798
799}
800
Note: See TracBrowser for help on using the browser.