]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/packethandler.cc
Include config.h only in .cc files
[thirdparty/pdns.git] / pdns / packethandler.cc
CommitLineData
bcf21dff 1/*
12c86877 2 PowerDNS Versatile Database Driven Nameserver
8dee0750 3 Copyright (C) 2002-2014 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
a640a9d4
BH
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
12c86877 8
f782fe38
MH
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
12c86877
BH
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 21*/
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
e8d78143 25#include "packetcache.hh"
12c86877 26#include "utility.hh"
01fde57c 27#include "base32.hh"
12c86877
BH
28#include <string>
29#include <sys/types.h>
bc28bef8 30#include <boost/algorithm/string.hpp>
35fe50c3 31#include <boost/foreach.hpp>
35fe50c3
BH
32#include "dnssecinfra.hh"
33#include "dnsseckeeper.hh"
12c86877
BH
34#include "dns.hh"
35#include "dnsbackend.hh"
36#include "ueberbackend.hh"
37#include "dnspacket.hh"
38#include "nameserver.hh"
39#include "distributor.hh"
40#include "logger.hh"
41#include "arguments.hh"
42#include "packethandler.hh"
43#include "statbag.hh"
44#include "resolver.hh"
45#include "communicator.hh"
46#include "dnsproxy.hh"
ba1a571d 47#include "version.hh"
357f6a75 48#include "common_startup.hh"
12c86877 49
51a3a4d4 50#if 0
2893c412
BH
51#undef DLOG
52#define DLOG(x) x
507823d1 53#endif
357f6a75 54
16f7d28d 55AtomicCounter PacketHandler::s_count;
d207ad63 56NetmaskGroup PacketHandler::s_allowNotifyFrom;
12c86877
BH
57extern string s_programname;
58
3194f0df
MZ
59enum root_referral {
60 NO_ROOT_REFERRAL,
61 LEAN_ROOT_REFERRAL,
62 FULL_ROOT_REFERRAL
63};
64
e59b5787 65PacketHandler::PacketHandler():B(s_programname), d_dk(&B)
12c86877 66{
16f7d28d 67 ++s_count;
8dee0750 68 d_doDNAME=::arg().mustDo("experimental-dname-processing");
e8d78143
BH
69 d_doRecursion= ::arg().mustDo("recursor");
70 d_logDNSDetails= ::arg().mustDo("log-dns-details");
71 d_doIPv6AdditionalProcessing = ::arg().mustDo("do-ipv6-additional-processing");
3194f0df
MZ
72 d_sendRootReferral = ::arg().mustDo("send-root-referral")
73 ? ( pdns_iequals(::arg()["send-root-referral"], "lean") ? LEAN_ROOT_REFERRAL : FULL_ROOT_REFERRAL )
74 : NO_ROOT_REFERRAL;
5704e107
PD
75 string fname= ::arg()["lua-prequery-script"];
76 if(fname.empty())
77 {
78 d_pdl = NULL;
79 }
80 else
81 {
82 d_pdl = new AuthLua(fname);
83 }
84
12c86877
BH
85}
86
3971cf53 87UeberBackend *PacketHandler::getBackend()
12c86877
BH
88{
89 return &B;
90}
91
92PacketHandler::~PacketHandler()
93{
94 --s_count;
95 DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
12c86877
BH
96}
97
8a63d3ce
BH
98void PacketHandler::addRootReferral(DNSPacket* r)
99{
100 // nobody reads what we output, but it appears to be the magic that shuts some nameservers up
c1ee5895 101 static const char*ips[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "199.7.91.13", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53",
bbd2b7ef 102 "192.36.148.17","192.58.128.30", "193.0.14.129", "199.7.83.42", "202.12.27.33"};
8a63d3ce
BH
103 static char templ[40];
104 strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
105
106 // add . NS records
107 DNSResourceRecord rr;
108 rr.qtype=QType::NS;
109 rr.ttl=518400;
110 rr.d_place=DNSResourceRecord::AUTHORITY;
111
112 for(char c='a';c<='m';++c) {
113 *templ=c;
114 rr.content=templ;
115 r->addRecord(rr);
116 }
117
3194f0df 118 if( d_sendRootReferral == LEAN_ROOT_REFERRAL )
bc28bef8
BH
119 return;
120
8a63d3ce
BH
121 // add the additional stuff
122
123 rr.ttl=3600000;
124 rr.qtype=QType::A;
125 rr.d_place=DNSResourceRecord::ADDITIONAL;
126
127 for(char c='a';c<='m';++c) {
128 *templ=c;
129 rr.qname=templ;
130 rr.content=ips[c-'a'];
131 r->addRecord(rr);
132 }
133}
12c86877 134
794c2f92
PD
135/** This adds DNSKEY records. Returns true if one was added */
136bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
35fe50c3
BH
137{
138 DNSResourceRecord rr;
35fe50c3
BH
139 bool haveOne=false;
140 DNSSECPrivateKey dpk;
141
ade1b1e9
BH
142 DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
143 BOOST_FOREACH(DNSSECKeeper::keyset_t::value_type value, keyset) {
35fe50c3 144 rr.qtype=QType::DNSKEY;
9e946c9b 145 rr.ttl=sd.default_ttl;
35fe50c3
BH
146 rr.qname=p->qdomain;
147 rr.content=value.first.getDNSKEY().getZoneRepresentation();
ade1b1e9 148 rr.auth=true;
35fe50c3
BH
149 r->addRecord(rr);
150 haveOne=true;
151 }
4a6ea260 152
cc8df07f 153 if(::arg().mustDo("direct-dnskey")) {
4a6ea260
PD
154 B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
155 while(B.get(rr)) {
6dae726d 156 rr.ttl=sd.default_ttl;
4a6ea260
PD
157 r->addRecord(rr);
158 haveOne=true;
159 }
160 }
161
35fe50c3
BH
162 return haveOne;
163}
164
165
794c2f92
PD
166/** This adds NSEC3PARAM records. Returns true if one was added */
167bool PacketHandler::addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd)
c3c89361 168{
c3c89361 169 DNSResourceRecord rr;
c3c89361
BH
170
171 NSEC3PARAMRecordContent ns3prc;
e0d84497 172 if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
c3c89361 173 rr.qtype=QType::NSEC3PARAM;
9e946c9b 174 rr.ttl=sd.default_ttl;
c3c89361 175 rr.qname=p->qdomain;
1c405b6a 176 ns3prc.d_flags = 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
c3c89361
BH
177 rr.content=ns3prc.getZoneRepresentation();
178 rr.auth = true;
179 r->addRecord(rr);
180 return true;
181 }
182 return false;
183}
184
185
49e8d5d5
KM
186// This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
187int PacketHandler::doChaosRequest(DNSPacket *p, DNSPacket *r, string &target)
12c86877
BH
188{
189 DNSResourceRecord rr;
8ca1a435 190
49e8d5d5
KM
191 if(p->qtype.getCode()==QType::TXT) {
192 if (pdns_iequals(target, "version.pdns") || pdns_iequals(target, "version.bind")) {
193 // modes: full, powerdns only, anonymous or custom
194 const static string mode=::arg()["version-string"];
8ca1a435 195
49e8d5d5
KM
196 if(mode.empty() || mode=="full")
197 rr.content=fullVersionString();
198 else if(mode=="powerdns")
199 rr.content="Served by PowerDNS - https://www.powerdns.com/";
200 else if(mode=="anonymous") {
8ca1a435 201 r->setRcode(RCode::ServFail);
8ca1a435
DB
202 return 0;
203 }
204 else
205 rr.content=mode;
49e8d5d5
KM
206 }
207 else if (pdns_iequals(target, "id.server")) {
208 // modes: disabled, hostname or custom
209 const static string id=::arg()["server-id"];
210
211 if (id == "disabled") {
212 r->setRcode(RCode::Refused);
213 return 0;
8ca1a435 214 }
49e8d5d5
KM
215 rr.content=id;
216 }
217 else {
218 r->setRcode(RCode::Refused);
219 return 0;
e5d684f9 220 }
e5d684f9 221
12c86877
BH
222 rr.ttl=5;
223 rr.qname=target;
49e8d5d5
KM
224 rr.qtype=QType::TXT;
225 rr.qclass=QClass::CHAOS;
12c86877 226 r->addRecord(rr);
12c86877
BH
227 return 1;
228 }
49e8d5d5
KM
229
230 r->setRcode(RCode::NotImp);
12c86877
BH
231 return 0;
232}
233
35fe50c3
BH
234vector<DNSResourceRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const string &target)
235{
236 vector<DNSResourceRecord> ret;
237 DNSResourceRecord rr;
238 string subdomain(target);
239 do {
82cc1f71
BH
240 if(subdomain == sd.qname) // stop at SOA
241 break;
35fe50c3
BH
242 B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
243 while(B.get(rr)) {
0da371d7 244 ret.push_back(rr); // this used to exclude auth NS records for some reason
35fe50c3
BH
245 }
246 if(!ret.empty())
247 return ret;
248 } while( chopOff( subdomain ) ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
249 return ret;
250}
251
8dee0750 252vector<DNSResourceRecord> PacketHandler::getBestDNAMESynth(DNSPacket *p, SOAData& sd, string &target)
253{
254 vector<DNSResourceRecord> ret;
255 DNSResourceRecord rr;
256 string prefix;
257 string subdomain(target);
258 do {
259 DLOG(L<<"Attempting DNAME lookup for "<<subdomain<<", sd.qname="<<sd.qname<<endl);
260
261 B.lookup(QType(QType::DNAME), subdomain, p, sd.domain_id);
262 while(B.get(rr)) {
263 ret.push_back(rr); // put in the original
264 rr.qtype = QType::CNAME;
265 rr.qname = prefix + rr.qname;
266 rr.content = prefix + rr.content;
dce1e90d 267 rr.auth = 0; // don't sign CNAME
8dee0750 268 target= rr.content;
269 ret.push_back(rr);
270 }
271 if(!ret.empty())
272 return ret;
273 string::size_type pos = subdomain.find('.');
274 if(pos != string::npos)
275 prefix+= subdomain.substr(0, pos+1);
276 if(subdomain == sd.qname) // stop at SOA
277 break;
278
279 } while( chopOff( subdomain ) ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
280 return ret;
281}
282
283
75a89ce6
PD
284// Return best matching wildcard or next closer name
285bool PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const string &target, string &wildcard, vector<DNSResourceRecord>* ret)
35fe50c3 286{
e3f388cd 287 ret->clear();
35fe50c3
BH
288 DNSResourceRecord rr;
289 string subdomain(target);
75a89ce6
PD
290 bool haveSomething=false;
291
292 wildcard=subdomain;
598b152c
RA
293 while( chopOff( subdomain ) && !haveSomething ) {
294 if (subdomain.empty()) {
295 B.lookup(QType(QType::ANY), "*", p, sd.domain_id);
296 } else {
297 B.lookup(QType(QType::ANY), "*."+subdomain, p, sd.domain_id);
298 }
35fe50c3 299 while(B.get(rr)) {
598b152c 300 if(rr.qtype == p->qtype || rr.qtype.getCode() == QType::CNAME || (p->qtype.getCode() == QType::ANY && rr.qtype.getCode() != QType::RRSIG))
e3f388cd 301 ret->push_back(rr);
75a89ce6 302 wildcard="*."+subdomain;
e3f388cd 303 haveSomething=true;
35fe50c3 304 }
75a89ce6
PD
305
306 if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
82cc1f71 307 break;
35fe50c3 308
75a89ce6
PD
309 B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
310 if (B.get(rr)) {
311 DLOG(L<<"No wildcard match, ancestor exists"<<endl);
312 while (B.get(rr)) ;
313 break;
314 }
315 wildcard=subdomain;
316 }
317
318 return haveSomething;
35fe50c3
BH
319}
320
12c86877 321/** dangling is declared true if we were unable to resolve everything */
d2323cd0 322int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
12c86877
BH
323{
324 DNSResourceRecord rr;
fd8bc993 325 SOAData sd;
313923a8 326 sd.db=0;
b636533b 327
b8e0f341
BH
328 if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
329 vector<DNSResourceRecord *> arrs=r->getAPRecords();
330 if(arrs.empty())
331 return 1;
332
12c86877
BH
333 DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
334
8513f025
BH
335 vector<DNSResourceRecord> crrs;
336
8c949c52 337 for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin(); i!=arrs.end(); ++i)
8513f025
BH
338 crrs.push_back(**i);
339
340 // we now have a copy, push_back on packet might reallocate!
8c949c52 341 for(vector<DNSResourceRecord>::const_iterator i=crrs.begin(); i!=crrs.end(); ++i) {
d2323cd0 342 if(r->d.aa && !i->qname.empty() && i->qtype.getCode()==QType::NS && !B.getSOA(i->qname,sd,p) && !retargeted) { // drop AA in case of non-SOA-level NS answer, except for root referral
76bf5f40 343 r->setA(false);
232f0877 344 // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
f6ba332a 345 }
fd8bc993 346
794c2f92 347 string content = stripDot(i->content);
b9bafae0
KM
348 if(i->qtype == QType::MX || i->qtype == QType::SRV) {
349 string::size_type pos = content.find_first_not_of("0123456789");
350 if(pos != string::npos)
351 boost::erase_head(content, pos);
352 trim_left(content);
353 }
794c2f92 354
fd8bc993
BH
355 QType qtypes[2];
356 qtypes[0]="A"; qtypes[1]="AAAA";
0595c0db 357 for(int n=0 ; n < d_doIPv6AdditionalProcessing + 1; ++n) {
a16e8e3a
BH
358 if (i->qtype.getCode()==QType::SRV) {
359 vector<string>parts;
794c2f92 360 stringtok(parts, content);
a16e8e3a
BH
361 if (parts.size() >= 3) {
362 B.lookup(qtypes[n],parts[2],p);
363 }
364 else
365 continue;
366 }
367 else {
794c2f92 368 B.lookup(qtypes[n], content, p);
a16e8e3a 369 }
4957a608 370 while(B.get(rr)) {
4957a608
BH
371 if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
372 DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
373 continue; // not adding out-of-zone additional data
374 }
33177493
BH
375 if(rr.auth && !endsOn(rr.qname, soadata.qname)) // don't sign out of zone data using the main key
376 rr.auth=false;
4957a608
BH
377 rr.d_place=DNSResourceRecord::ADDITIONAL;
378 r->addRecord(rr);
379 }
b636533b 380 }
12c86877
BH
381 }
382 }
383 return 1;
384}
385
35fe50c3 386
9e946c9b 387void PacketHandler::emitNSEC(const std::string& begin, const std::string& end, const std::string& toNSEC, const SOAData& sd, DNSPacket *r, int mode)
35fe50c3 388{
50eb4144 389 // cerr<<"We should emit '"<<begin<<"' - ('"<<toNSEC<<"') - '"<<end<<"'"<<endl;
35fe50c3
BH
390 NSECRecordContent nrc;
391 nrc.d_set.insert(QType::RRSIG);
392 nrc.d_set.insert(QType::NSEC);
50eb4144
KM
393 if(pdns_iequals(sd.qname, begin)) {
394 nrc.d_set.insert(QType::SOA);
9b30cd1a 395 nrc.d_set.insert(QType::DNSKEY);
50eb4144 396 }
35fe50c3
BH
397
398 DNSResourceRecord rr;
b563f71b 399 B.lookup(QType(QType::ANY), begin, NULL, sd.domain_id);
35fe50c3 400 while(B.get(rr)) {
b563f71b 401 if(rr.qtype.getCode() == QType::NS || rr.auth)
50eb4144 402 nrc.d_set.insert(rr.qtype.getCode());
35fe50c3 403 }
50eb4144 404
35fe50c3
BH
405 nrc.d_next=end;
406
407 rr.qname=begin;
b5baefaf 408 rr.ttl = sd.default_ttl;
35fe50c3
BH
409 rr.qtype=QType::NSEC;
410 rr.content=nrc.getZoneRepresentation();
75a89ce6 411 rr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
35fe50c3 412 rr.auth = true;
50eb4144 413
35fe50c3
BH
414 r->addRecord(rr);
415}
416
3971cf53 417void emitNSEC3(UeberBackend& 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)
5c3bf2db 418{
50eb4144 419 // cerr<<"We should emit NSEC3 '"<<toBase32Hex(begin)<<"' - ('"<<toNSEC3<<"') - '"<<toBase32Hex(end)<<"' (unhashed: '"<<unhashed<<"')"<<endl;
5c3bf2db 420 NSEC3RecordContent n3rc;
c3c89361 421 n3rc.d_salt=ns3prc.d_salt;
b9dba5c1 422 n3rc.d_flags = ns3prc.d_flags;
c3c89361 423 n3rc.d_iterations = ns3prc.d_iterations;
64747e59 424 n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
5c3bf2db 425
b5baefaf
PD
426 DNSResourceRecord rr;
427 if(!unhashed.empty()) {
b8adb30d 428 B.lookup(QType(QType::ANY), unhashed, NULL, sd.domain_id);
b5baefaf 429 while(B.get(rr)) {
b8adb30d 430 if(rr.qtype.getCode() && (rr.qtype.getCode() == QType::NS || rr.auth)) // skip empty non-terminals
b5baefaf
PD
431 n3rc.d_set.insert(rr.qtype.getCode());
432 }
c3c89361 433
50eb4144
KM
434 if (pdns_iequals(sd.qname, unhashed)) {
435 n3rc.d_set.insert(QType::SOA);
b5baefaf
PD
436 n3rc.d_set.insert(QType::NSEC3PARAM);
437 n3rc.d_set.insert(QType::DNSKEY);
438 }
c3c89361 439 }
b5baefaf 440
b8adb30d 441 if (n3rc.d_set.size() && !(n3rc.d_set.size() == 1 && n3rc.d_set.count(QType::NS)))
b5baefaf 442 n3rc.d_set.insert(QType::RRSIG);
50eb4144 443
5c3bf2db
BH
444 n3rc.d_nexthash=end;
445
1bad4190 446 rr.qname=dotConcat(toBase32Hex(begin), sd.qname);
b5baefaf 447 rr.ttl = sd.default_ttl;
5c3bf2db
BH
448 rr.qtype=QType::NSEC3;
449 rr.content=n3rc.getZoneRepresentation();
75a89ce6 450 rr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
5c3bf2db 451 rr.auth = true;
50eb4144 452
5c3bf2db
BH
453 r->addRecord(rr);
454}
455
64747e59
BH
456void 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)
457{
458 ::emitNSEC3(B, ns3prc, sd, unhashed, begin, end, toNSEC3, r, mode);
459
460}
01fde57c 461
75a89ce6
PD
462/*
463 mode 0 = No Data Responses, QTYPE is not DS
b5baefaf 464 mode 1 = No Data Responses, QTYPE is DS
75a89ce6
PD
465 mode 2 = Wildcard No Data Responses
466 mode 3 = Wildcard Answer Responses
467 mode 4 = Name Error Responses
dcb8c5d7 468 mode 5 = Direct NSEC request
35fe50c3 469*/
c5c4fbdc 470void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const string& target, const string& wildcard, const string& auth, int mode)
01fde57c 471{
52e0d783
KM
472 if(!p->d_dnssecOk && mode != 5)
473 return;
474
c3c89361 475 NSEC3PARAMRecordContent ns3rc;
6affea24 476 // cerr<<"Doing NSEC3PARAM lookup for '"<<auth<<"', "<<p->qdomain<<"|"<<p->qtype.getName()<<": ";
22c5aa60
BH
477 bool narrow;
478 if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
6affea24 479 // cerr<<"Present, narrow="<<narrow<<endl;
dcb8c5d7
PD
480 if (mode != 5) // no direct NSEC3 please
481 addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
9b30cd1a
BH
482 }
483 else {
6affea24 484 // cerr<<"Not present"<<endl;
c5c4fbdc 485 addNSEC(p, r, target, wildcard, auth, mode);
9b30cd1a 486 }
01fde57c
BH
487}
488
96cf053d 489static void incrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
22c5aa60 490{
96cf053d 491 if(raw.empty())
22c5aa60 492 return;
96cf053d 493
0c3e047d 494 for(string::size_type pos=raw.size(); pos; ) {
22c5aa60 495 --pos;
0c3e047d 496 unsigned char c = (unsigned char)raw[pos];
22c5aa60 497 ++c;
0c3e047d 498 raw[pos] = (char) c;
22c5aa60
BH
499 if(c)
500 break;
501 }
502}
503
96cf053d 504static void decrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
af3ffdf1 505{
96cf053d 506 if(raw.empty())
af3ffdf1 507 return;
0c3e047d 508
0c3e047d 509 for(string::size_type pos=raw.size(); pos; ) {
af3ffdf1 510 --pos;
0c3e047d 511 unsigned char c = (unsigned char)raw[pos];
af3ffdf1 512 --c;
0c3e047d 513 raw[pos] = (char) c;
af3ffdf1
BH
514 if(c != 0xff)
515 break;
516 }
517}
518
519
3a741d7f 520bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, string& unhashed, string& before, string& after, int mode)
22c5aa60
BH
521{
522 bool ret;
523 if(narrow) { // nsec3-narrow
524 ret=true;
525 before=hashed;
b5baefaf 526 if(decrement) {
af3ffdf1 527 decrementHash(before);
b5baefaf
PD
528 unhashed.clear();
529 }
22c5aa60
BH
530 after=hashed;
531 incrementHash(after);
532 }
533 else {
5f5fd462 534 if (decrement || mode <= 1)
8c1a6d6d
KM
535 before.clear();
536 else
537 before=' ';
1bad4190 538 ret=db->getBeforeAndAfterNamesAbsolute(id, toBase32Hex(hashed), unhashed, before, after);
20b4fa88
BH
539 before=fromBase32Hex(before);
540 after=fromBase32Hex(after);
22c5aa60
BH
541 }
542 // cerr<<"rgetNSEC3Hashes: "<<hashed<<", "<<unhashed<<", "<<before<<", "<<after<<endl;
543 return ret;
544}
545
c5c4fbdc 546void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const string& target, const string& wildcard, const string& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
01fde57c 547{
53977f80
KM
548 DLOG(L<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
549
5c3bf2db 550 SOAData sd;
79ba7763 551 if(!B.getSOAUncached(auth, sd)) {
53977f80 552 DLOG(L<<"Could not get SOA for domain");
5c3bf2db
BH
553 return;
554 }
53977f80 555
3a741d7f 556 bool doNextcloser = false;
75a89ce6 557 string unhashed, hashed, before, after;
f0306634 558 string closest;
d88babea 559 DNSResourceRecord rr;
53977f80 560
75a89ce6 561 if (mode == 2 || mode == 3 || mode == 4) {
f0306634 562 closest=wildcard;
53977f80 563 (void) chopOff(closest);
f0306634
KM
564 } else
565 closest=target;
53977f80 566
75a89ce6 567 // add matching NSEC3 RR
b50efd61 568 if (mode != 3) {
3a741d7f 569 unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
75a89ce6 570 hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
b8adb30d 571 DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 572
996df946 573 if(!B.getDirectNSECx(sd.domain_id, hashed, QType(QType::NSEC3), before, rr))
d88babea 574 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
3a741d7f 575
2e9c8710 576 if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
54c9247e 577 DLOG(L<<"No matching NSEC3, do closest (provable) encloser"<<endl);
3a741d7f 578
54c9247e 579 bool doBreak = false;
3a741d7f
KM
580 DNSResourceRecord rr;
581 while( chopOff( closest ) && (closest != sd.qname)) { // stop at SOA
582 B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
54c9247e
KM
583 while(B.get(rr))
584 if (rr.auth)
585 doBreak = true;
586 if(doBreak)
3a741d7f 587 break;
3a741d7f
KM
588 }
589 doNextcloser = true;
590 unhashed=closest;
b27640fa 591 hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
3a741d7f
KM
592 DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
593
996df946 594 if(!B.getDirectNSECx(sd.domain_id, hashed, QType(QType::NSEC3), before, rr))
d88babea 595 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
3a741d7f
KM
596 }
597
d88babea
KM
598 if (!after.empty()) {
599 DLOG(L<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
600 emitNSEC3(ns3rc, sd, unhashed, before, after, target, r, mode);
601 } else if(!before.empty())
602 r->addRecord(rr);
16cf9135 603 }
75a89ce6
PD
604
605 // add covering NSEC3 RR
3a741d7f 606 if ((mode >= 2 && mode <= 4) || doNextcloser) {
c5c4fbdc 607 string next(target);
75a89ce6
PD
608 do {
609 unhashed=next;
610 }
611 while( chopOff( next ) && !pdns_iequals(next, closest));
612
613 hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
b8adb30d 614 DLOG(L<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
996df946 615 if(!B.getDirectNSECx(sd.domain_id, hashed, QType(QType::NSEC3), before, rr)) {
d88babea
KM
616 getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
617 DLOG(L<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
618 emitNSEC3( ns3rc, sd, unhashed, before, after, target, r, mode);
619 } else if(!before.empty())
620 r->addRecord(rr);
75a89ce6 621 }
53977f80 622
75a89ce6 623 // wildcard denial
7bb8e202 624 if (mode == 2 || mode == 4) {
75a89ce6
PD
625 unhashed=dotConcat("*", closest);
626
627 hashed=hashQNameWithSalt(ns3rc.d_iterations, ns3rc.d_salt, unhashed);
b8adb30d 628 DLOG(L<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
53977f80 629
996df946 630 if(!B.getDirectNSECx(sd.domain_id, hashed, QType(QType::NSEC3), before, rr)) {
d88babea
KM
631 getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
632 DLOG(L<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
633 emitNSEC3( ns3rc, sd, unhashed, before, after, target, r, mode);
634 } else if(!before.empty())
635 r->addRecord(rr);
75a89ce6 636 }
01fde57c 637}
35fe50c3 638
c5c4fbdc 639void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const string& target, const string& wildcard, const string& auth, int mode)
35fe50c3 640{
53977f80 641 DLOG(L<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
35fe50c3 642
53977f80 643 SOAData sd;
79ba7763 644 if(!B.getSOAUncached(auth, sd)) {
6affea24 645 DLOG(L<<"Could not get SOA for domain"<<endl);
35fe50c3
BH
646 return;
647 }
648
649 string before,after;
996df946
KM
650 DNSResourceRecord rr;
651
652 rr.auth=false;
653 if(!B.getDirectNSECx(sd.domain_id, toLower(labelReverse(makeRelative(target, auth))), QType(QType::NSEC), before, rr)) {
654 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
655 emitNSEC(before, after, target, sd, r, mode);
656 } else if(rr.auth) {
657 if (mode == 5)
658 rr.d_place=DNSResourceRecord::ANSWER;
659 r->addRecord(rr);
660 }
b5baefaf 661
337dd27b
KM
662 if (mode == 2 || mode == 4) {
663 // wildcard NO-DATA or wildcard denial
628ab42d 664 before.clear();
337dd27b
KM
665 string closest(wildcard);
666 if (mode == 4) {
667 (void) chopOff(closest);
668 closest=dotConcat("*", closest);
669 }
996df946
KM
670 rr.auth=false;
671 if(!B.getDirectNSECx(sd.domain_id, toLower(labelReverse(makeRelative(closest, auth))), QType(QType::NSEC), before, rr)) {
672 sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
673 emitNSEC(before, after, target, sd, r, mode);
674 } else if(rr.auth)
675 r->addRecord(rr);
75a89ce6 676 }
35fe50c3
BH
677 return;
678}
679
12c86877
BH
680/* Semantics:
681
682- only one backend owns the SOA of a zone
683- only one AXFR per zone at a time - double startTransaction should fail
684- backends need to implement transaction semantics
685
686
687How BindBackend would implement this:
688 startTransaction makes a file
689 feedRecord sends everything to that file
690 commitTransaction moves that file atomically over the regular file, and triggers a reload
691 rollbackTransaction removes the file
692
693
694How PostgreSQLBackend would implement this:
695 startTransaction starts a sql transaction, which also deletes all records
696 feedRecord is an insert statement
697 commitTransaction commits the transaction
698 rollbackTransaction aborts it
699
700How MySQLBackend would implement this:
701 (good question!)
702
703*/
704
705int PacketHandler::trySuperMaster(DNSPacket *p)
7108e055
PD
706{
707 if(p->d_tcp)
708 {
709 // do it right now if the client is TCP
710 // rarely happens
711 return trySuperMasterSynchronous(p);
712 }
713 else
714 {
715 // queue it if the client is on UDP
716 Communicator.addTrySuperMasterRequest(p);
717 return 0;
718 }
719}
720
721int PacketHandler::trySuperMasterSynchronous(DNSPacket *p)
12c86877
BH
722{
723 Resolver::res_t nsset;
724 try {
725 Resolver resolver;
092f210a 726 uint32_t theirserial;
0c01dd7c
BH
727 resolver.getSoaSerial(p->getRemote(),p->qdomain, &theirserial);
728 resolver.resolve(p->getRemote(), p->qdomain.c_str(), QType::NS, &nsset);
12c86877
BH
729 }
730 catch(ResolverException &re) {
7108e055 731 L<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< p->getRemote() <<": "<<re.reason<<endl;
12c86877
BH
732 return RCode::ServFail;
733 }
734
39b23e69
RK
735 // check if the returned records are NS records
736 bool haveNS=false;
737 BOOST_FOREACH(const DNSResourceRecord& ns, nsset) {
738 if(ns.qtype.getCode()==QType::NS)
739 haveNS=true;
740 }
741
742 if(!haveNS) {
5d979026 743 L<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< p->getRemote()<<endl;
39b23e69
RK
744 return RCode::ServFail;
745 }
746
719f9024 747 string nameserver, account;
12c86877 748 DNSBackend *db;
719f9024 749 if(!B.superMasterBackend(p->getRemote(), p->qdomain, nsset, &nameserver, &account, &db)) {
c16de2e7 750 L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<". Remote nameservers: "<<endl;
5fe5f5bb 751 BOOST_FOREACH(class DNSResourceRecord& rr, nsset) {
c16de2e7
RK
752 if(rr.qtype.getCode()==QType::NS)
753 L<<Logger::Error<<rr.content<<endl;
a7372c6f 754 }
12c86877
BH
755 return RCode::Refused;
756 }
8c80c4f4 757 try {
719f9024 758 db->createSlaveDomain(p->getRemote(), p->qdomain, nameserver, account);
8c80c4f4 759 }
3f81d239 760 catch(PDNSException& ae) {
8c80c4f4
BH
761 L<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<p->getRemote()<<": "<<ae.reason<<endl;
762 return RCode::ServFail;
763 }
9245fd9f 764 L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<p->getRemote()<<endl;
12c86877
BH
765 return RCode::NoError;
766}
767
3777f434 768int PacketHandler::processNotify(DNSPacket *p)
12c86877
BH
769{
770 /* now what?
771 was this notification from an approved address?
772 We determine our internal SOA id (via UeberBackend)
773 We determine the SOA at our (known) master
774 if master is higher -> do stuff
775 */
e8d78143 776 if(!::arg().mustDo("slave")) {
12c86877
BH
777 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
778 return RCode::NotImp;
779 }
d207ad63
RK
780
781 if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote )) {
782 L<<Logger::Notice<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but remote is not in allow-notify-from"<<endl;
783 return RCode::Refused;
784 }
785
12c86877
BH
786 DNSBackend *db=0;
787 DomainInfo di;
f7fb7022 788 di.serial = 0;
c38f6509 789 if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
12c86877
BH
790 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
791 return trySuperMaster(p);
792 }
793
e8d78143 794 if(::arg().contains("trusted-notification-proxy", p->getRemote())) {
f7fb7022
BH
795 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
796 if(di.masters.empty()) {
797 L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
798 return RCode::Refused;
799 }
f7fb7022
BH
800 }
801 else if(!db->isMaster(p->qdomain, p->getRemote())) {
12c86877
BH
802 L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
803 return RCode::Refused;
804 }
e6e4836c 805
7f3d870e 806 // ok, we've done our checks
a16e8e3a 807 di.backend = 0;
d06799d4 808 Communicator.addSlaveCheckRequest(di, p->d_remote);
7f3d870e 809 return 0;
12c86877
BH
810}
811
5158c495
BH
812bool validDNSName(const string &name)
813{
814 string::size_type pos, length=name.length();
815 char c;
816 for(pos=0; pos < length; ++pos) {
817 c=name[pos];
818 if(!((c >= 'a' && c <= 'z') ||
4957a608
BH
819 (c >= 'A' && c <= 'Z') ||
820 (c >= '0' && c <= '9') ||
da8e6ae1 821 c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
5158c495
BH
822 return false;
823 }
824 return true;
825}
826
12c86877
BH
827DNSPacket *PacketHandler::question(DNSPacket *p)
828{
5704e107 829 DNSPacket *ret;
3e8216c8 830 int policyres = PolicyDecision::PASS;
5704e107
PD
831
832 if(d_pdl)
833 {
834 ret=d_pdl->prequery(p);
835 if(ret)
836 return ret;
837 }
838
bb6e54fe 839 if(p->d.rd) {
1566533a 840 static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
bb6e54fe 841 rdqueries++;
842 }
843
3e8216c8
PD
844 if(LPE)
845 {
846 policyres = LPE->police(p, NULL);
847 }
848
849 if (policyres == PolicyDecision::DROP)
850 return NULL;
851
852 if (policyres == PolicyDecision::TRUNCATE) {
853 ret=p->replyPacket(); // generate an empty reply packet
854 ret->d.tc = 1;
855 ret->commitD();
856 return ret;
857 }
858
ff76e8b4 859 bool shouldRecurse=false;
5704e107 860 ret=questionOrRecurse(p, &shouldRecurse);
ff76e8b4
BH
861 if(shouldRecurse) {
862 DP->sendPacket(p);
863 }
3e8216c8
PD
864 if(LPE) {
865 int policyres=LPE->police(p, ret);
866 if(policyres == PolicyDecision::DROP) {
867 delete ret;
868 return NULL;
869 }
870 if (policyres == PolicyDecision::TRUNCATE) {
871 delete ret;
872 ret=p->replyPacket(); // generate an empty reply packet
873 ret->d.tc = 1;
874 ret->commitD();
875 }
876
877 }
ff76e8b4
BH
878 return ret;
879}
880
c5c4fbdc 881void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const std::string& target, const std::string& wildcard, SOAData& sd)
35fe50c3
BH
882{
883 DNSResourceRecord rr;
884 rr.qname=sd.qname;
885 rr.qtype=QType::SOA;
886 rr.content=serializeSOAData(sd);
794c2f92
PD
887 rr.ttl=min(sd.ttl, sd.default_ttl);
888 rr.signttl=sd.ttl;
35fe50c3
BH
889 rr.domain_id=sd.domain_id;
890 rr.d_place=DNSResourceRecord::AUTHORITY;
0957a99f 891 rr.auth = 1;
af7d3ea6 892 rr.scopeMask = sd.scopeMask;
35fe50c3 893 r->addRecord(rr);
6865d5c0 894
52e0d783 895 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 896 addNSECX(p, r, target, wildcard, sd.qname, 4);
6865d5c0
KM
897
898 r->setRcode(RCode::NXDomain);
35fe50c3
BH
899}
900
c5c4fbdc 901void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const std::string& target, const std::string& wildcard, SOAData& sd, int mode)
35fe50c3
BH
902{
903 DNSResourceRecord rr;
904 rr.qname=sd.qname;
905 rr.qtype=QType::SOA;
906 rr.content=serializeSOAData(sd);
907 rr.ttl=sd.ttl;
794c2f92
PD
908 rr.ttl=min(sd.ttl, sd.default_ttl);
909 rr.signttl=sd.ttl;
35fe50c3
BH
910 rr.domain_id=sd.domain_id;
911 rr.d_place=DNSResourceRecord::AUTHORITY;
bccefefa 912 rr.auth = 1;
35fe50c3 913 r->addRecord(rr);
ed9c3a50 914
52e0d783 915 if(d_dk.isSecuredZone(sd.qname))
c5c4fbdc 916 addNSECX(p, r, target, wildcard, sd.qname, mode);
9951e2d0
KM
917
918 S.ringAccount("noerror-queries",p->qdomain+"/"+p->qtype.getName());
35fe50c3
BH
919}
920
921
922bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const string& dsname)
923{
e4090157 924 //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
35fe50c3
BH
925 B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
926 DNSResourceRecord rr;
927 bool gotOne=false;
928 while(B.get(rr)) {
929 gotOne=true;
930 rr.d_place = DNSResourceRecord::AUTHORITY;
931 r->addRecord(rr);
932 }
933 return gotOne;
934}
935
d2323cd0 936bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target, bool retargeted)
35fe50c3
BH
937{
938 vector<DNSResourceRecord> rrset = getBestReferralNS(p, sd, target);
939 if(rrset.empty())
940 return false;
941
6affea24 942 DLOG(L<<"The best NS is: "<<rrset.begin()->qname<<endl);
35fe50c3 943 BOOST_FOREACH(DNSResourceRecord rr, rrset) {
6affea24 944 DLOG(L<<"\tadding '"<<rr.content<<"'"<<endl);
35fe50c3
BH
945 rr.d_place=DNSResourceRecord::AUTHORITY;
946 r->addRecord(rr);
947 }
d2323cd0
PD
948 if(!retargeted)
949 r->setA(false);
35fe50c3 950
52e0d783 951 if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->qname))
c5c4fbdc 952 addNSECX(p, r, rrset.begin()->qname, "", sd.qname, 1);
35fe50c3
BH
953
954 return true;
955}
956
957void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const string &target)
958{
959 if(!p->d_dnssecOk)
df554502 960 return; // Don't send dnssec info to non validating resolvers.
52e0d783 961
d3e7090c 962 if(!d_dk.isSecuredZone(sd.qname))
fbcdac7e
BH
963 return;
964
52e0d783 965 addNSECX(p, r, target, "", sd.qname, 5);
7f5bf0ba 966 if(pdns_iequals(sd.qname, p->qdomain)) {
794c2f92
PD
967 addDNSKEY(p, r, sd);
968 addNSEC3PARAM(p, r, sd);
70b18120 969 }
35fe50c3
BH
970}
971
8dee0750 972bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, string &target)
973{
974 if(!d_doDNAME)
975 return false;
976 DLOG(L<<Logger::Warning<<"Let's try DNAME.."<<endl);
977 vector<DNSResourceRecord> rrset = getBestDNAMESynth(p, sd, target);
978 if(!rrset.empty()) {
979 BOOST_FOREACH(DNSResourceRecord& rr, rrset) {
980 rr.d_place = DNSResourceRecord::ANSWER;
981 r->addRecord(rr);
982 }
983 return true;
984 }
985 return false;
986}
75a89ce6 987bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, string &target, string &wildcard, bool& retargeted, bool& nodata)
35fe50c3 988{
e3f388cd 989 retargeted = nodata = false;
c5c4fbdc 990 string bestmatch;
35fe50c3 991
e3f388cd 992 vector<DNSResourceRecord> rrset;
75a89ce6 993 if(!getBestWildcard(p, sd, target, wildcard, &rrset))
35fe50c3
BH
994 return false;
995
e3f388cd 996 if(rrset.empty()) {
6affea24 997 DLOG(L<<"Wildcard matched something, but not of the correct type"<<endl);
e3f388cd
BH
998 nodata=true;
999 }
1000 else {
6affea24 1001 DLOG(L<<"The best wildcard match: "<<rrset.begin()->qname<<endl);
e3f388cd 1002 BOOST_FOREACH(DNSResourceRecord rr, rrset) {
bcb8aebe 1003 rr.wildcardname = rr.qname;
c5c4fbdc 1004 rr.qname=bestmatch=target;
bcb8aebe 1005
e3f388cd
BH
1006 if(rr.qtype.getCode() == QType::CNAME) {
1007 retargeted=true;
1008 target=rr.content;
1009 }
1010
6affea24 1011 DLOG(L<<"\tadding '"<<rr.content<<"'"<<endl);
e3f388cd
BH
1012 rr.d_place=DNSResourceRecord::ANSWER;
1013 r->addRecord(rr);
35fe50c3 1014 }
35fe50c3 1015 }
52e0d783 1016 if(d_dk.isSecuredZone(sd.qname) && !nodata) {
c5c4fbdc 1017 addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
35fe50c3
BH
1018 }
1019 return true;
1020}
1021
ff76e8b4
BH
1022//! Called by the Distributor to ask a question. Returns 0 in case of an error
1023DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
1024{
1025 *shouldRecurse=false;
12c86877
BH
1026 DNSResourceRecord rr;
1027 SOAData sd;
81c486ad 1028
12c86877
BH
1029 string subdomain="";
1030 string soa;
1031 int retargetcount=0;
8d3cbffa 1032 set<string, CIStringCompare> authSet;
35fe50c3
BH
1033
1034 vector<DNSResourceRecord> rrset;
1035 bool weDone=0, weRedirected=0, weHaveUnauth=0;
d59b894d 1036 string haveAlias;
12c86877 1037
0c127168 1038 DNSPacket *r=0;
78bcb858 1039 bool noCache=false;
a16e8e3a
BH
1040
1041 if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
1042 L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
1043 S.inc("corrupt-packets");
41aacb6a 1044 S.ringAccount("remotes-corrupt", p->d_remote);
a16e8e3a
BH
1045 return 0;
1046 }
1047
78bcb858
BH
1048 if(p->d_havetsig) {
1049 string keyname, secret;
1050 TSIGRecordContent trc;
1051 if(!checkForCorrectTSIG(p, &B, &keyname, &secret, &trc)) {
0c127168 1052 r=p->replyPacket(); // generate an empty reply packet
78bcb858
BH
1053 if(d_logDNSDetails)
1054 L<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
f7a69a4c
RA
1055 // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
1056 if (p->d.opcode == Opcode::Update)
914353ca
KM
1057 r->setRcode(RCode::Refused);
1058 else
f7a69a4c 1059 r->setRcode(RCode::NotAuth);
78bcb858
BH
1060 return r;
1061 }
1062 p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
1063 noCache=true;
1064 }
1065
0c127168
BH
1066 r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
1067
12c86877 1068 try {
12c86877
BH
1069
1070 // XXX FIXME do this in DNSPacket::parse ?
1071
5158c495 1072 if(!validDNSName(p->qdomain)) {
bb5903e2 1073 if(d_logDNSDetails)
8b1ed874 1074 L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
eefd15f9 1075 S.inc("corrupt-packets");
41aacb6a 1076 S.ringAccount("remotes-corrupt", p->d_remote);
aa3d0f19 1077 S.inc("servfail-packets");
8b1ed874
BH
1078 r->setRcode(RCode::ServFail);
1079 return r;
12c86877
BH
1080 }
1081 if(p->d.opcode) { // non-zero opcode (again thanks RA!)
1082 if(p->d.opcode==Opcode::Update) {
71f758e0 1083 S.inc("dnsupdate-queries");
f7a69a4c 1084 int res=processUpdate(p);
63cb8c10 1085 if (res == RCode::Refused)
71f758e0 1086 S.inc("dnsupdate-refused");
63cb8c10 1087 else if (res != RCode::ServFail)
71f758e0 1088 S.inc("dnsupdate-answers");
f7a69a4c
RA
1089 r->setRcode(res);
1090 r->setOpcode(Opcode::Update);
1091 return r;
12c86877
BH
1092 }
1093 else if(p->d.opcode==Opcode::Notify) {
93aecccc 1094 S.inc("incoming-notifications");
4957a608
BH
1095 int res=processNotify(p);
1096 if(res>=0) {
4957a608
BH
1097 r->setRcode(res);
1098 r->setOpcode(Opcode::Notify);
1099 return r;
1100 }
f3a91936 1101 delete r;
4957a608 1102 return 0;
12c86877
BH
1103 }
1104
1105 L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
1106
12c86877
BH
1107 r->setRcode(RCode::NotImp);
1108 return r;
1109 }
c2413a68 1110
357f6a75 1111 // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
12c86877 1112
0e7f49b5 1113 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
83a825e0 1114
dc45a198
BH
1115 if(p->qtype.getCode()==QType::IXFR) {
1116 r->setRcode(RCode::NotImp);
1117 return r;
1118 }
1119
12c86877 1120 string target=p->qdomain;
c76a16b7 1121
49e8d5d5
KM
1122 // catch chaos qclass requests
1123 if(p->qclass == QClass::CHAOS) {
1124 if (doChaosRequest(p,r,target))
1125 goto sendit;
1126 else
1127 return r;
1128 }
12c86877 1129
e8e0e41c 1130 // we only know about qclass IN (and ANY), send NotImp for everything else.
c76a16b7
KM
1131 if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
1132 r->setRcode(RCode::NotImp);
c4ac5865
BH
1133 return r;
1134 }
12c86877 1135
ec62f3c0
KM
1136 // send TC for udp ANY query if any-to-tcp is enabled.
1137 if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
abc8f3f9 1138 r->d.tc = 1;
1139 r->commitD();
1140 return r;
1141 }
1142
49e8d5d5 1143 // for qclass ANY the response should never be authoritative unless the response covers all classes.
c76a16b7 1144 if(p->qclass==QClass::ANY)
12c86877 1145 r->setA(false);
c76a16b7 1146
12c86877
BH
1147
1148 retargeted:;
35fe50c3 1149 if(retargetcount > 10) { // XXX FIXME, retargetcount++?
75c8ebb4
KM
1150 L<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
1151 delete r;
1152 r=p->replyPacket();
12c86877 1153 r->setRcode(RCode::ServFail);
35fe50c3 1154 return r;
12c86877 1155 }
507823d1 1156
81c486ad 1157 if(!B.getAuth(p, &sd, target)) {
0e7f49b5 1158 DLOG(L<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
8b5da9f2 1159 if(r->d.ra) {
0e7f49b5 1160 DLOG(L<<Logger::Error<<"Recursion is available for this remote, doing that"<<endl);
8b5da9f2
BH
1161 *shouldRecurse=true;
1162 delete r;
1163 return 0;
1164 }
dd722153 1165
3af99aee 1166 if(!retargetcount)
8d3cbffa 1167 r->setA(false); // drop AA if we never had a SOA in the first place
3194f0df 1168 if( d_sendRootReferral != NO_ROOT_REFERRAL ) {
82cc1f71
BH
1169 DLOG(L<<Logger::Warning<<"Adding root-referral"<<endl);
1170 addRootReferral(r);
5e61f18c 1171 }
35fe50c3 1172 else {
ed5a90d3
PD
1173 if (!retargetcount)
1174 r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
82cc1f71 1175 }
507823d1
BH
1176 goto sendit;
1177 }
1178 DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
8d3cbffa 1179 authSet.insert(sd.qname);
12c86877 1180
3e8216c8
PD
1181 if(!retargetcount) r->qdomainzone=sd.qname;
1182
1183
fbcdac7e 1184 if(pdns_iequals(sd.qname, p->qdomain)) {
794c2f92
PD
1185 if(p->qtype.getCode() == QType::DNSKEY)
1186 {
1187 if(addDNSKEY(p, r, sd))
1188 goto sendit;
1189 }
1190 else if(p->qtype.getCode() == QType::NSEC3PARAM)
1191 {
1192 if(addNSEC3PARAM(p,r, sd))
1193 goto sendit;
1194 }
fbcdac7e
BH
1195 }
1196
507823d1 1197 if(p->qtype.getCode() == QType::SOA && pdns_iequals(sd.qname, p->qdomain)) {
52e0d783 1198 rr.qname=sd.qname;
507823d1
BH
1199 rr.qtype=QType::SOA;
1200 rr.content=serializeSOAData(sd);
1201 rr.ttl=sd.ttl;
1202 rr.domain_id=sd.domain_id;
1203 rr.d_place=DNSResourceRecord::ANSWER;
d24589bc 1204 rr.auth = true;
507823d1
BH
1205 r->addRecord(rr);
1206 goto sendit;
1207 }
12c86877 1208
35fe50c3 1209 // this TRUMPS a cname!
52e0d783
KM
1210 if(p->qtype.getCode() == QType::NSEC && d_dk.isSecuredZone(sd.qname) && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
1211 addNSEC(p, r, target, "", sd.qname, 5);
cac7e485 1212 goto sendit;
12c86877 1213 }
571726e9 1214
35fe50c3 1215 // this TRUMPS a cname!
ec62f3c0
KM
1216 if(p->qtype.getCode() == QType::RRSIG) {
1217 L<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
1218 r->setRcode(RCode::NotImp);
52e0d783 1219 goto sendit;
cac7e485 1220 }
35fe50c3 1221
571726e9 1222 DLOG(L<<"Checking for referrals first, unless this is a DS query"<<endl);
d2323cd0 1223 if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
571726e9
PD
1224 goto sendit;
1225
1226 DLOG(L<<"Got no referrals, trying ANY"<<endl);
1227
35fe50c3
BH
1228 // see what we get..
1229 B.lookup(QType(QType::ANY), target, p, sd.domain_id);
1230 rrset.clear();
d59b894d 1231 haveAlias.clear();
8dee0750 1232 weDone = weRedirected = weHaveUnauth = false;
35fe50c3
BH
1233
1234 while(B.get(rr)) {
df554502
KM
1235 if (p->qtype.getCode() == QType::ANY) {
1236 if (rr.qtype.getCode() == QType::RRSIG) // RRSIGS are added later any way.
1237 continue; // TODO: this actually means addRRSig should check if the RRSig is already there.
1238 if (!p->d_dnssecOk && (rr.qtype.getCode() == QType:: DNSKEY || rr.qtype.getCode() == QType::NSEC3PARAM))
1239 continue; // Don't send dnssec info to non validating resolvers.
1240 }
794c2f92 1241
5b739515 1242 // cerr<<"Auth: "<<rr.auth<<", "<<(rr.qtype == p->qtype)<<", "<<rr.qtype.getName()<<endl;
35fe50c3 1243 if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth)
82cc1f71 1244 weDone=1;
5b739515
BH
1245 // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
1246 if((rr.qtype == p->qtype && !rr.auth) || (rr.qtype.getCode() == QType::NS && (!rr.auth || !pdns_iequals(sd.qname, rr.qname))))
82cc1f71 1247 weHaveUnauth=1;
35fe50c3
BH
1248
1249 if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME)
82cc1f71 1250 weRedirected=1;
1dfd8ada 1251
d59b894d 1252 if(DP && rr.qtype.getCode() == QType::ALIAS) {
1253 haveAlias=rr.content;
1254 }
1255
1dfd8ada
MZ
1256 // Filter out all SOA's and add them in later
1257 if(rr.qtype.getCode() == QType::SOA)
1258 continue;
1259
35fe50c3 1260 rrset.push_back(rr);
12c86877
BH
1261 }
1262
1dfd8ada
MZ
1263 /* Add in SOA if required */
1264 if( pdns_iequals( target, sd.qname ) ) {
1265 rr.qtype = QType::SOA;
1266 rr.content = serializeSOAData(sd);
1267 rr.qname = sd.qname;
1268 rr.ttl = sd.ttl;
1269 rr.domain_id = sd.domain_id;
1270 rr.auth = true;
1271 rrset.push_back(rr);
1272 }
1273
8dee0750 1274
d59b894d 1275 DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
849bd7f1
BH
1276 if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
1277 DLOG(L<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl);
c5c4fbdc 1278 makeNOError(p, r, target, "", sd, 1);
849bd7f1
BH
1279 goto sendit;
1280 }
12c86877 1281
d59b894d 1282 if(!haveAlias.empty() && !weDone) {
1283 DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
1284 DP->completePacket(r, haveAlias, target);
1285 return 0;
1286 }
1287
35fe50c3 1288 if(rrset.empty()) {
75a89ce6 1289 DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
0a0f4112
PD
1290 if(p->qtype.getCode() == QType::DS)
1291 {
1292 DLOG(L<<"DS query found no direct result, trying referral now"<<endl);
d2323cd0 1293 if(tryReferral(p, r, sd, target, retargetcount))
0a0f4112
PD
1294 {
1295 DLOG(L<<"got referral for DS query"<<endl);
1296 goto sendit;
1297 }
1298 }
1299
d59b894d 1300
571726e9 1301 DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
e3f388cd 1302 bool wereRetargeted(false), nodata(false);
75a89ce6
PD
1303 string wildcard;
1304 if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
82cc1f71 1305 if(wereRetargeted) {
3e8216c8 1306 if(!retargetcount) r->qdomainwild=wildcard;
82cc1f71
BH
1307 retargetcount++;
1308 goto retargeted;
1309 }
c5c4fbdc
PD
1310 if(nodata)
1311 makeNOError(p, r, target, wildcard, sd, 2);
1312
82cc1f71 1313 goto sendit;
8e50cd4c 1314 }
8dee0750 1315 else if(tryDNAME(p, r, sd, target)) {
1316 retargetcount++;
1317 goto retargeted;
1318 }
a87b7e3f
PD
1319 else
1320 {
c5c4fbdc
PD
1321 if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
1322 makeNXDomain(p, r, target, wildcard, sd);
a87b7e3f
PD
1323 }
1324
82cc1f71
BH
1325 goto sendit;
1326 }
232f0877 1327
35fe50c3
BH
1328 if(weRedirected) {
1329 BOOST_FOREACH(rr, rrset) {
82cc1f71
BH
1330 if(rr.qtype.getCode() == QType::CNAME) {
1331 r->addRecord(rr);
1332 target = rr.content;
1333 retargetcount++;
1334 goto retargeted;
4957a608 1335 }
82cc1f71 1336 }
82cc1f71 1337 }
35fe50c3 1338 else if(weDone) {
b5baefaf 1339 bool haveRecords = false;
35fe50c3 1340 BOOST_FOREACH(rr, rrset) {
b5baefaf 1341 if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.qtype.getCode() && rr.auth) {
4957a608 1342 r->addRecord(rr);
b5baefaf
PD
1343 haveRecords = true;
1344 }
82cc1f71 1345 }
4957a608 1346
b5baefaf
PD
1347 if (haveRecords) {
1348 if(p->qtype.getCode() == QType::ANY)
1349 completeANYRecords(p, r, sd, target);
82cc1f71 1350 }
b5baefaf 1351 else
c5c4fbdc 1352 makeNOError(p, r, rr.qname, "", sd, 0);
4957a608 1353
35fe50c3 1354 goto sendit;
82cc1f71 1355 }
35fe50c3 1356 else if(weHaveUnauth) {
6affea24 1357 DLOG(L<<"Have unauth data, so need to hunt for best NS records"<<endl);
d2323cd0 1358 if(tryReferral(p, r, sd, target, retargetcount))
82cc1f71 1359 goto sendit;
2b18bcf3
AT
1360 // check whether this could be fixed easily
1361 if (*(rr.qname.rbegin()) == '.') {
1362 L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnssec rectify-zone " <<sd.qname<<")"<<endl;
1363 } else {
1364 L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnssec rectify-zone "<<sd.qname<<endl;
1365 }
82cc1f71
BH
1366 }
1367 else {
6affea24 1368 DLOG(L<<"Have some data, but not the right data"<<endl);
c5c4fbdc 1369 makeNOError(p, r, target, "", sd, 0);
82cc1f71 1370 }
12c86877
BH
1371
1372 sendit:;
d2323cd0 1373 if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
f3a91936 1374 delete r;
12c86877 1375 return 0;
f3a91936 1376 }
8ea10bfc 1377
f33065be 1378 editSOA(d_dk, sd.qname, r);
c76f6f48 1379
1380 BOOST_FOREACH(const DNSResourceRecord& rr, r->getRRS()) {
606018f2 1381 if(rr.scopeMask) {
c28bf199
RK
1382 noCache=1;
1383 break;
606018f2 1384 }
1385 }
e02d0a59 1386 if(p->d_dnssecOk)
8d3cbffa 1387 addRRSigs(d_dk, B, authSet, r->getRRS());
f3a91936 1388
e02d0a59 1389 r->wrapup(); // needed for inserting in cache
78bcb858 1390 if(!noCache)
75fde355 1391 PC.insert(p, r, false, r->getMinTTL()); // in the packet cache
12c86877
BH
1392 }
1393 catch(DBException &e) {
f89fb897 1394 L<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
25e7af37
KM
1395 delete r;
1396 r=p->replyPacket(); // generate an empty reply packet
12c86877 1397 r->setRcode(RCode::ServFail);
eefd15f9 1398 S.inc("servfail-packets");
12c86877
BH
1399 S.ringAccount("servfail-queries",p->qdomain);
1400 }
3f81d239 1401 catch(PDNSException &e) {
63822d0e 1402 L<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
31d9bb01 1403 throw; // we WANT to die at this point
86113ac9 1404 }
5172cb78 1405 catch(std::exception &e) {
f7fb7022 1406 L<<Logger::Error<<"Exception building answer packet ("<<e.what()<<") sending out servfail"<<endl;
8ea10bfc 1407 delete r;
25e7af37 1408 r=p->replyPacket(); // generate an empty reply packet
8ea10bfc
BH
1409 r->setRcode(RCode::ServFail);
1410 S.inc("servfail-packets");
1411 S.ringAccount("servfail-queries",p->qdomain);
1412 }
12c86877
BH
1413 return r;
1414
1415}
1416