]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rfc2136handler.cc
Merge pull request #9070 from rgacogne/boost-173
[thirdparty/pdns.git] / pdns / rfc2136handler.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "packethandler.hh"
5 #include "qtype.hh"
6 #include "dnspacket.hh"
7 #include "auth-caches.hh"
8 #include "statbag.hh"
9 #include "dnsseckeeper.hh"
10 #include "base64.hh"
11 #include "base32.hh"
12
13 #include "misc.hh"
14 #include "arguments.hh"
15 #include "resolver.hh"
16 #include "dns_random.hh"
17 #include "backends/gsql/ssql.hh"
18 #include "communicator.hh"
19
20 extern StatBag S;
21 extern CommunicatorClass Communicator;
22
23 std::mutex PacketHandler::s_rfc2136lock;
24
25 // Implement section 3.2.1 and 3.2.2 of RFC2136
26 int PacketHandler::checkUpdatePrerequisites(const DNSRecord *rr, DomainInfo *di) {
27 if (rr->d_ttl != 0)
28 return RCode::FormErr;
29
30 // 3.2.1 and 3.2.2 check content length.
31 if ( (rr->d_class == QClass::NONE || rr->d_class == QClass::ANY) && rr->d_clen != 0)
32 return RCode::FormErr;
33
34 bool foundRecord=false;
35 DNSResourceRecord rec;
36 di->backend->lookup(QType(QType::ANY), rr->d_name, di->id);
37 while(di->backend->get(rec)) {
38 if (!rec.qtype.getCode())
39 continue;
40 if ((rr->d_type != QType::ANY && rec.qtype == rr->d_type) || rr->d_type == QType::ANY)
41 foundRecord=true;
42 }
43
44 // Section 3.2.1
45 if (rr->d_class == QClass::ANY && !foundRecord) {
46 if (rr->d_type == QType::ANY)
47 return RCode::NXDomain;
48 if (rr->d_type != QType::ANY)
49 return RCode::NXRRSet;
50 }
51
52 // Section 3.2.2
53 if (rr->d_class == QClass::NONE && foundRecord) {
54 if (rr->d_type == QType::ANY)
55 return RCode::YXDomain;
56 if (rr->d_type != QType::ANY)
57 return RCode::YXRRSet;
58 }
59
60 return RCode::NoError;
61 }
62
63
64 // Method implements section 3.4.1 of RFC2136
65 int PacketHandler::checkUpdatePrescan(const DNSRecord *rr) {
66 // The RFC stats that d_class != ZCLASS, but we only support the IN class.
67 if (rr->d_class != QClass::IN && rr->d_class != QClass::NONE && rr->d_class != QClass::ANY)
68 return RCode::FormErr;
69
70 QType qtype = QType(rr->d_type);
71
72 if (! qtype.isSupportedType())
73 return RCode::FormErr;
74
75 if ((rr->d_class == QClass::NONE || rr->d_class == QClass::ANY) && rr->d_ttl != 0)
76 return RCode::FormErr;
77
78 if (rr->d_class == QClass::ANY && rr->d_clen != 0)
79 return RCode::FormErr;
80
81 if (qtype.isMetadataType())
82 return RCode::FormErr;
83
84 if (rr->d_class != QClass::ANY && qtype.getCode() == QType::ANY)
85 return RCode::FormErr;
86
87 return RCode::NoError;
88 }
89
90
91 // Implements section 3.4.2 of RFC2136
92 uint PacketHandler::performUpdate(const string &msgPrefix, const DNSRecord *rr, DomainInfo *di, bool isPresigned, bool* narrow, bool* haveNSEC3, NSEC3PARAMRecordContent *ns3pr, bool *updatedSerial) {
93
94 QType rrType = QType(rr->d_type);
95
96 if (rrType == QType::NSEC || rrType == QType::NSEC3) {
97 g_log<<Logger::Warning<<msgPrefix<<"Trying to add/update/delete "<<rr->d_name<<"|"<<rrType.getName()<<". These are generated records, ignoring!"<<endl;
98 return 0;
99 }
100
101 if (!isPresigned && ((!::arg().mustDo("direct-dnskey") && rrType == QType::DNSKEY) || rrType == QType::RRSIG)) {
102 g_log<<Logger::Warning<<msgPrefix<<"Trying to add/update/delete "<<rr->d_name<<"|"<<rrType.getName()<<" in non-presigned zone, ignoring!"<<endl;
103 return 0;
104 }
105
106 if ((rrType == QType::NSEC3PARAM || rrType == QType::DNSKEY) && rr->d_name != di->zone) {
107 g_log<<Logger::Warning<<msgPrefix<<"Trying to add/update/delete "<<rr->d_name<<"|"<<rrType.getName()<<", "<<rrType.getName()<<" must be at zone apex, ignoring!"<<endl;
108 return 0;
109 }
110
111
112 uint changedRecords = 0;
113 DNSResourceRecord rec;
114 vector<DNSResourceRecord> rrset, recordsToDelete;
115 set<DNSName> delnonterm, insnonterm; // used to (at the end) fix ENT records.
116
117
118 if (rr->d_class == QClass::IN) { // 3.4.2.2 QClass::IN means insert or update
119 DLOG(g_log<<msgPrefix<<"Add/Update record (QClass == IN) "<<rr->d_name<<"|"<<rrType.getName()<<endl);
120
121 if (rrType == QType::NSEC3PARAM) {
122 g_log<<Logger::Notice<<msgPrefix<<"Adding/updating NSEC3PARAM for zone, resetting ordernames."<<endl;
123
124 NSEC3PARAMRecordContent nsec3param(rr->d_content->getZoneRepresentation(), di->zone.toString() /* FIXME400 huh */);
125 *narrow = false; // adding a NSEC3 will cause narrow mode to be dropped, as you cannot specify that in a NSEC3PARAM record
126 d_dk.setNSEC3PARAM(di->zone, nsec3param, (*narrow));
127
128 *haveNSEC3 = d_dk.getNSEC3PARAM(di->zone, ns3pr, narrow);
129
130 vector<DNSResourceRecord> rrs;
131 set<DNSName> qnames, nssets, dssets;
132 di->backend->list(di->zone, di->id);
133 while (di->backend->get(rec)) {
134 qnames.insert(rec.qname);
135 if(rec.qtype.getCode() == QType::NS && rec.qname != di->zone)
136 nssets.insert(rec.qname);
137 if(rec.qtype.getCode() == QType::DS)
138 dssets.insert(rec.qname);
139 }
140
141 DNSName shorter;
142 for(const auto& qname: qnames) {
143 shorter = qname;
144 int ddepth = 0;
145 do {
146 if(qname == di->zone)
147 break;
148 if(nssets.count(shorter))
149 ++ddepth;
150 } while(shorter.chopOff());
151
152 DNSName ordername = DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, qname)));
153 if (! *narrow && (ddepth == 0 || (ddepth == 1 && nssets.count(qname)))) {
154 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, ordername, (ddepth == 0 ));
155
156 if (nssets.count(qname)) {
157 if (ns3pr->d_flags)
158 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), false, QType::NS );
159 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), false, QType::A);
160 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), false, QType::AAAA);
161 }
162 } else {
163 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), (ddepth == 0));
164 }
165 if (ddepth == 1 || dssets.count(qname)) // FIXME400 && ?
166 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, ordername, false, QType::DS);
167 }
168 return 1;
169 }
170
171
172
173 bool foundRecord = false;
174 di->backend->lookup(rrType, rr->d_name, di->id);
175 while (di->backend->get(rec)) {
176 rrset.push_back(rec);
177 foundRecord = true;
178 }
179
180 if (foundRecord) {
181
182 if (rrType == QType::SOA) { // SOA updates require the serial to be higher than the current
183 SOAData sdOld, sdUpdate;
184 DNSResourceRecord *oldRec = &rrset.front();
185 fillSOAData(oldRec->content, sdOld);
186 oldRec->setContent(rr->d_content->getZoneRepresentation());
187 fillSOAData(oldRec->content, sdUpdate);
188 if (rfc1982LessThan(sdOld.serial, sdUpdate.serial)) {
189 di->backend->replaceRRSet(di->id, oldRec->qname, oldRec->qtype, rrset);
190 *updatedSerial = true;
191 changedRecords++;
192 g_log<<Logger::Notice<<msgPrefix<<"Replacing record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
193 } else {
194 g_log<<Logger::Notice<<msgPrefix<<"Provided serial ("<<sdUpdate.serial<<") is older than the current serial ("<<sdOld.serial<<"), ignoring SOA update."<<endl;
195 }
196
197 // It's not possible to have multiple CNAME's with the same NAME. So we always update.
198 } else if (rrType == QType::CNAME) {
199 int changedCNames = 0;
200 for (auto& i : rrset) {
201 if (i.ttl != rr->d_ttl || i.content != rr->d_content->getZoneRepresentation()) {
202 i.ttl = rr->d_ttl;
203 i.setContent(rr->d_content->getZoneRepresentation());
204 changedCNames++;
205 }
206 }
207 if (changedCNames > 0) {
208 di->backend->replaceRRSet(di->id, rr->d_name, rrType, rrset);
209 g_log<<Logger::Notice<<msgPrefix<<"Replacing record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
210 changedRecords += changedCNames;
211 } else {
212 g_log<<Logger::Notice<<msgPrefix<<"Replace for record "<<rr->d_name<<"|"<<rrType.getName()<<" requested, but no changes made."<<endl;
213 }
214
215 // In any other case, we must check if the TYPE and RDATA match to provide an update (which effectively means a update of TTL)
216 } else {
217 int updateTTL=0;
218 foundRecord = false;
219 bool lowerCase = false;
220 if (rrType.getCode() == QType::PTR ||
221 rrType.getCode() == QType::MX ||
222 rrType.getCode() == QType::SRV) {
223 lowerCase = true;
224 }
225 string content = rr->d_content->getZoneRepresentation();
226 if (lowerCase) content = toLower(content);
227 for (auto& i : rrset) {
228 string icontent = i.getZoneRepresentation();
229 if (lowerCase) icontent = toLower(icontent);
230 if (rrType == i.qtype.getCode() && icontent == content) {
231 foundRecord=true;
232 if (i.ttl != rr->d_ttl) {
233 i.ttl = rr->d_ttl;
234 updateTTL++;
235 }
236 }
237 }
238 if (updateTTL > 0) {
239 di->backend->replaceRRSet(di->id, rr->d_name, rrType, rrset);
240 g_log<<Logger::Notice<<msgPrefix<<"Replacing record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
241 changedRecords += updateTTL;
242 } else {
243 g_log<<Logger::Notice<<msgPrefix<<"Replace for record "<<rr->d_name<<"|"<<rrType.getName()<<" requested, but no changes made."<<endl;
244 }
245 }
246
247 // ReplaceRRSet dumps our ordername and auth flag, so we need to correct it if we have changed records.
248 // We can take the auth flag from the first RR in the set, as the name is different, so should the auth be.
249 if (changedRecords > 0) {
250 bool auth = rrset.front().auth;
251
252 if(*haveNSEC3) {
253 DNSName ordername;
254 if(! *narrow)
255 ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, rr->d_name)));
256
257 if (*narrow)
258 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), auth);
259 else
260 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, ordername, auth);
261 if(!auth || rrType == QType::DS) {
262 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::NS);
263 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::A);
264 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::AAAA);
265 }
266
267 } else { // NSEC
268 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, rr->d_name.makeRelative(di->zone), auth);
269 if(!auth || rrType == QType::DS) {
270 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::A);
271 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::AAAA);
272 }
273 }
274 }
275
276 } // if (foundRecord)
277
278 // If we haven't found a record that matches, we must add it.
279 if (! foundRecord) {
280 g_log<<Logger::Notice<<msgPrefix<<"Adding record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
281 delnonterm.insert(rr->d_name); // always remove any ENT's in the place where we're going to add a record.
282 auto newRec = DNSResourceRecord::fromWire(*rr);
283 newRec.domain_id = di->id;
284 newRec.auth = (rr->d_name == di->zone || rrType.getCode() != QType::NS);
285 di->backend->feedRecord(newRec, DNSName());
286 changedRecords++;
287
288
289 // because we added a record, we need to fix DNSSEC data.
290 DNSName shorter(rr->d_name);
291 bool auth=newRec.auth;
292 bool fixDS = (rrType == QType::DS);
293
294 if (di->zone != shorter) { // Everything at APEX is auth=1 && no ENT's
295 do {
296
297 if (di->zone == shorter)
298 break;
299
300 bool foundShorter = false;
301 di->backend->lookup(QType(QType::ANY), shorter, di->id);
302 while (di->backend->get(rec)) {
303 if (rec.qname == rr->d_name && rec.qtype == QType::DS)
304 fixDS = true;
305 if (shorter != rr->d_name)
306 foundShorter = true;
307 if (rec.qtype == QType::NS) // are we inserting below a delegate?
308 auth=false;
309 }
310
311 if (!foundShorter && auth && shorter != rr->d_name) // haven't found any record at current level, insert ENT.
312 insnonterm.insert(shorter);
313 if (foundShorter)
314 break; // if we find a shorter record, we can stop searching
315 } while(shorter.chopOff());
316 }
317
318 if(*haveNSEC3)
319 {
320 DNSName ordername;
321 if(! *narrow)
322 ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, rr->d_name)));
323
324 if (*narrow)
325 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), auth);
326 else
327 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, ordername, auth);
328
329 if (fixDS)
330 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, ordername, true, QType::DS);
331
332 if(!auth)
333 {
334 if (ns3pr->d_flags)
335 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::NS);
336 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::A);
337 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::AAAA);
338 }
339 }
340 else // NSEC
341 {
342 DNSName ordername=rr->d_name.makeRelative(di->zone);
343 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, ordername, auth);
344 if (fixDS) {
345 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, ordername, true, QType::DS);
346 }
347 if(!auth) {
348 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::A);
349 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), false, QType::AAAA);
350 }
351 }
352
353
354 // If we insert an NS, all the records below it become non auth - so, we're inserting a delegate.
355 // Auth can only be false when the rr->d_name is not the zone
356 if (auth == false && rrType == QType::NS) {
357 DLOG(g_log<<msgPrefix<<"Going to fix auth flags below "<<rr->d_name<<endl);
358 insnonterm.clear(); // No ENT's are needed below delegates (auth=0)
359 vector<DNSName> qnames;
360 di->backend->listSubZone(rr->d_name, di->id);
361 while(di->backend->get(rec)) {
362 if (rec.qtype.getCode() && rec.qtype.getCode() != QType::DS && rr->d_name != rec.qname) // Skip ENT, DS and our already corrected record.
363 qnames.push_back(rec.qname);
364 }
365 for(vector<DNSName>::const_iterator qname=qnames.begin(); qname != qnames.end(); ++qname) {
366 if(*haveNSEC3) {
367 DNSName ordername;
368 if(! *narrow)
369 ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, *qname)));
370
371 if (*narrow)
372 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr->d_name, DNSName(), auth); // FIXME400 no *qname here?
373 else
374 di->backend->updateDNSSECOrderNameAndAuth(di->id, *qname, ordername, auth);
375
376 if (ns3pr->d_flags)
377 di->backend->updateDNSSECOrderNameAndAuth(di->id, *qname, DNSName(), false, QType::NS);
378 }
379 else { // NSEC
380 DNSName ordername=DNSName(*qname).makeRelative(di->zone);
381 di->backend->updateDNSSECOrderNameAndAuth(di->id, *qname, ordername, false, QType::NS);
382 }
383
384 di->backend->updateDNSSECOrderNameAndAuth(di->id, *qname, DNSName(), false, QType::A);
385 di->backend->updateDNSSECOrderNameAndAuth(di->id, *qname, DNSName(), false, QType::AAAA);
386 }
387 }
388 }
389 } // rr->d_class == QClass::IN
390
391
392 // Delete records - section 3.4.2.3 and 3.4.2.4 with the exception of the 'always leave 1 NS rule' as that's handled by
393 // the code that calls this performUpdate().
394 if ((rr->d_class == QClass::ANY || rr->d_class == QClass::NONE) && rrType != QType::SOA) { // never delete a SOA.
395 DLOG(g_log<<msgPrefix<<"Deleting records: "<<rr->d_name<<"; QClass:"<<rr->d_class<<"; rrType: "<<rrType.getName()<<endl);
396
397 if (rrType == QType::NSEC3PARAM) {
398 g_log<<Logger::Notice<<msgPrefix<<"Deleting NSEC3PARAM from zone, resetting ordernames."<<endl;
399 if (rr->d_class == QClass::ANY)
400 d_dk.unsetNSEC3PARAM(rr->d_name);
401 else if (rr->d_class == QClass::NONE) {
402 NSEC3PARAMRecordContent nsec3rr(rr->d_content->getZoneRepresentation(), di->zone.toString() /* FIXME400 huh */);
403 if (ns3pr->getZoneRepresentation() == nsec3rr.getZoneRepresentation())
404 d_dk.unsetNSEC3PARAM(rr->d_name);
405 else
406 return 0;
407 } else
408 return 0;
409
410 // We retrieve new values, other RR's in this update package might need it as well.
411 *haveNSEC3 = d_dk.getNSEC3PARAM(di->zone, ns3pr, narrow);
412
413 vector<DNSResourceRecord> rrs;
414 set<DNSName> qnames, nssets, dssets, ents;
415 di->backend->list(di->zone, di->id);
416 while (di->backend->get(rec)) {
417 qnames.insert(rec.qname);
418 if(rec.qtype.getCode() == QType::NS && rec.qname != di->zone)
419 nssets.insert(rec.qname);
420 if(rec.qtype.getCode() == QType::DS)
421 dssets.insert(rec.qname);
422 if(!rec.qtype.getCode())
423 ents.insert(rec.qname);
424 }
425
426 DNSName shorter;
427 string hashed;
428 for(const DNSName& qname : qnames) {
429 shorter = qname;
430 int ddepth = 0;
431 do {
432 if(qname == di->zone)
433 break;
434 if(nssets.count(shorter))
435 ++ddepth;
436 } while(shorter.chopOff());
437
438 DNSName ordername=qname.makeRelative(di->zone);
439 if (!ents.count(qname) && (ddepth == 0 || (ddepth == 1 && nssets.count(qname)))) {
440 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, ordername, (ddepth == 0));
441
442 if (nssets.count(qname)) {
443 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), false, QType::A);
444 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), false, QType::AAAA);
445 }
446 } else {
447 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, DNSName(), (ddepth == 0));
448 }
449 if (ddepth == 1 || dssets.count(qname))
450 di->backend->updateDNSSECOrderNameAndAuth(di->id, qname, ordername, true, QType::DS);
451 }
452 return 1;
453 } // end of NSEC3PARAM delete block
454
455
456 di->backend->lookup(rrType, rr->d_name, di->id);
457 while(di->backend->get(rec)) {
458 if (rr->d_class == QClass::ANY) { // 3.4.2.3
459 if (rec.qname == di->zone && (rec.qtype == QType::NS || rec.qtype == QType::SOA)) // Never delete all SOA and NS's
460 rrset.push_back(rec);
461 else
462 recordsToDelete.push_back(rec);
463 }
464 if (rr->d_class == QClass::NONE) { // 3.4.2.4
465 if (rrType == rec.qtype && rec.getZoneRepresentation() == rr->d_content->getZoneRepresentation())
466 recordsToDelete.push_back(rec);
467 else
468 rrset.push_back(rec);
469 }
470 }
471
472 if (recordsToDelete.size()) {
473 di->backend->replaceRRSet(di->id, rr->d_name, rrType, rrset);
474 g_log<<Logger::Notice<<msgPrefix<<"Deleting record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
475 changedRecords += recordsToDelete.size();
476
477
478 // If we've removed a delegate, we need to reset ordername/auth for some records.
479 if (rrType == QType::NS && rr->d_name != di->zone) {
480 vector<DNSName> belowOldDelegate, nsRecs, updateAuthFlag;
481 di->backend->listSubZone(rr->d_name, di->id);
482 while (di->backend->get(rec)) {
483 if (rec.qtype.getCode()) // skip ENT records, they are always auth=false
484 belowOldDelegate.push_back(rec.qname);
485 if (rec.qtype.getCode() == QType::NS && rec.qname != rr->d_name)
486 nsRecs.push_back(rec.qname);
487 }
488
489 for(auto &belowOldDel: belowOldDelegate)
490 {
491 bool isBelowDelegate = false;
492 for(const auto & ns: nsRecs) {
493 if (ns.isPartOf(belowOldDel)) {
494 isBelowDelegate=true;
495 break;
496 }
497 }
498 if (!isBelowDelegate)
499 updateAuthFlag.push_back(belowOldDel);
500 }
501
502 for (const auto &changeRec:updateAuthFlag) {
503 if(*haveNSEC3) {
504 DNSName ordername;
505 if(! *narrow)
506 ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, changeRec)));
507
508 di->backend->updateDNSSECOrderNameAndAuth(di->id, changeRec, ordername, true);
509 }
510 else { // NSEC
511 DNSName ordername=changeRec.makeRelative(di->zone);
512 di->backend->updateDNSSECOrderNameAndAuth(di->id, changeRec, ordername, true);
513 }
514 }
515 }
516
517 // Fix ENT records.
518 // We must check if we have a record below the current level and if we removed the 'last' record
519 // on that level. If so, we must insert an ENT record.
520 // We take extra care here to not 'include' the record that we just deleted. Some backends will still return it as they only reload on a commit.
521 bool foundDeeper = false, foundOtherWithSameName = false;
522 di->backend->listSubZone(rr->d_name, di->id);
523 while (di->backend->get(rec)) {
524 if (rec.qname == rr->d_name && !count(recordsToDelete.begin(), recordsToDelete.end(), rec))
525 foundOtherWithSameName = true;
526 if (rec.qname != rr->d_name && rec.qtype.getCode() != QType::NS) //Skip NS records, as this would be a delegate that we can ignore as this does not require us to create a ENT
527 foundDeeper = true;
528 }
529
530 if (foundDeeper && !foundOtherWithSameName) {
531 insnonterm.insert(rr->d_name);
532 } else if (!foundOtherWithSameName) {
533 // If we didn't have to insert an ENT, we might have deleted a record at very deep level
534 // and we must then clean up the ENT's above the deleted record.
535 DNSName shorter(rr->d_name);
536 while (shorter != di->zone) {
537 shorter.chopOff();
538 bool foundRealRR = false;
539 bool foundEnt = false;
540
541 // The reason for a listSubZone here is because might go up the tree and find the ENT of another branch
542 // consider these non ENT-records:
543 // b.c.d.e.test.com
544 // b.d.e.test.com
545 // if we delete b.c.d.e.test.com, we go up to d.e.test.com and then find b.d.e.test.com because that's below d.e.test.com.
546 // At that point we can stop deleting ENT's because the tree is in tact again.
547 di->backend->listSubZone(shorter, di->id);
548
549 while (di->backend->get(rec)) {
550 if (rec.qtype.getCode())
551 foundRealRR = true;
552 else
553 foundEnt = true;
554 }
555 if (!foundRealRR) {
556 if (foundEnt) // only delete the ENT if we actually found one.
557 delnonterm.insert(shorter);
558 } else
559 break;
560 }
561 }
562 } else { // if (recordsToDelete.size())
563 g_log<<Logger::Notice<<msgPrefix<<"Deletion for record "<<rr->d_name<<"|"<<rrType.getName()<<" requested, but not found."<<endl;
564 }
565 } // (End of delete block d_class == ANY || d_class == NONE
566
567
568
569 //Insert and delete ENT's
570 if (insnonterm.size() > 0 || delnonterm.size() > 0) {
571 DLOG(g_log<<msgPrefix<<"Updating ENT records - "<<insnonterm.size()<<"|"<<delnonterm.size()<<endl);
572 di->backend->updateEmptyNonTerminals(di->id, insnonterm, delnonterm, false);
573 for (const auto &i: insnonterm) {
574 string hashed;
575 if(*haveNSEC3)
576 {
577 DNSName ordername;
578 if(! *narrow)
579 ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, i)));
580 di->backend->updateDNSSECOrderNameAndAuth(di->id, i, ordername, true);
581 }
582 }
583 }
584
585 return changedRecords;
586 }
587
588 int PacketHandler::forwardPacket(const string &msgPrefix, const DNSPacket& p, const DomainInfo& di) {
589 vector<string> forward;
590 B.getDomainMetadata(p.qdomain, "FORWARD-DNSUPDATE", forward);
591
592 if (forward.size() == 0 && ! ::arg().mustDo("forward-dnsupdate")) {
593 g_log<<Logger::Notice<<msgPrefix<<"Not configured to forward to master, returning Refused."<<endl;
594 return RCode::Refused;
595 }
596
597 for(const auto& remote : di.masters) {
598 g_log<<Logger::Notice<<msgPrefix<<"Forwarding packet to master "<<remote<<endl;
599
600 ComboAddress local;
601 if (remote.sin4.sin_family == AF_INET && !::arg()["query-local-address"].empty()) {
602 local = ComboAddress(::arg()["query-local-address"]);
603 } else if(remote.sin4.sin_family == AF_INET6 && !::arg()["query-local-address6"].empty()) {
604 local = ComboAddress(::arg()["query-local-address6"]);
605 } else {
606 continue;
607 }
608 int sock = makeQuerySocket(local, false); // create TCP socket. RFC2136 section 6.2 seems to be ok with this.
609 if(sock < 0) {
610 g_log<<Logger::Error<<msgPrefix<<"Error creating socket: "<<stringerror()<<endl;
611 continue;
612 }
613
614 if( connect(sock, (struct sockaddr*)&remote, remote.getSocklen()) < 0 ) {
615 g_log<<Logger::Error<<msgPrefix<<"Failed to connect to "<<remote.toStringWithPort()<<": "<<stringerror()<<endl;
616 try {
617 closesocket(sock);
618 }
619 catch(const PDNSException& e) {
620 g_log<<Logger::Error<<"Error closing master forwarding socket after connect() failed: "<<e.reason<<endl;
621 }
622 continue;
623 }
624
625 DNSPacket l_forwardPacket(p);
626 l_forwardPacket.setID(dns_random_uint16());
627 l_forwardPacket.setRemote(&remote);
628 uint16_t len=htons(l_forwardPacket.getString().length());
629 string buffer((const char*)&len, 2);
630 buffer.append(l_forwardPacket.getString());
631 if(write(sock, buffer.c_str(), buffer.length()) < 0) {
632 g_log<<Logger::Error<<msgPrefix<<"Unable to forward update message to "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
633 try {
634 closesocket(sock);
635 }
636 catch(const PDNSException& e) {
637 g_log<<Logger::Error<<"Error closing master forwarding socket after write() failed: "<<e.reason<<endl;
638 }
639 continue;
640 }
641
642 int res = waitForData(sock, 10, 0);
643 if (!res) {
644 g_log<<Logger::Error<<msgPrefix<<"Timeout waiting for reply from master at "<<remote.toStringWithPort()<<endl;
645 try {
646 closesocket(sock);
647 }
648 catch(const PDNSException& e) {
649 g_log<<Logger::Error<<"Error closing master forwarding socket after a timeout occurred: "<<e.reason<<endl;
650 }
651 continue;
652 }
653 if (res < 0) {
654 g_log<<Logger::Error<<msgPrefix<<"Error waiting for answer from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
655 try {
656 closesocket(sock);
657 }
658 catch(const PDNSException& e) {
659 g_log<<Logger::Error<<"Error closing master forwarding socket after an error occurred: "<<e.reason<<endl;
660 }
661 continue;
662 }
663
664 unsigned char lenBuf[2];
665 ssize_t recvRes;
666 recvRes = recv(sock, &lenBuf, sizeof(lenBuf), 0);
667 if (recvRes < 0 || static_cast<size_t>(recvRes) < sizeof(lenBuf)) {
668 g_log<<Logger::Error<<msgPrefix<<"Could not receive data (length) from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
669 try {
670 closesocket(sock);
671 }
672 catch(const PDNSException& e) {
673 g_log<<Logger::Error<<"Error closing master forwarding socket after recv() failed: "<<e.reason<<endl;
674 }
675 continue;
676 }
677 size_t packetLen = lenBuf[0]*256+lenBuf[1];
678
679 buffer.resize(packetLen);
680 recvRes = recv(sock, &buffer.at(0), packetLen, 0);
681 if (recvRes < 0) {
682 g_log<<Logger::Error<<msgPrefix<<"Could not receive data (dnspacket) from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
683 try {
684 closesocket(sock);
685 }
686 catch(const PDNSException& e) {
687 g_log<<Logger::Error<<"Error closing master forwarding socket after recv() failed: "<<e.reason<<endl;
688 }
689 continue;
690 }
691 try {
692 closesocket(sock);
693 }
694 catch(const PDNSException& e) {
695 g_log<<Logger::Error<<"Error closing master forwarding socket: "<<e.reason<<endl;
696 }
697
698 try {
699 MOADNSParser mdp(false, buffer.data(), static_cast<unsigned int>(recvRes));
700 g_log<<Logger::Info<<msgPrefix<<"Forward update message to "<<remote.toStringWithPort()<<", result was RCode "<<mdp.d_header.rcode<<endl;
701 return mdp.d_header.rcode;
702 }
703 catch (...) {
704 g_log<<Logger::Error<<msgPrefix<<"Failed to parse response packet from master at "<<remote.toStringWithPort()<<endl;
705 continue;
706 }
707 }
708 g_log<<Logger::Error<<msgPrefix<<"Failed to forward packet to master(s). Returning ServFail."<<endl;
709 return RCode::ServFail;
710
711 }
712
713 int PacketHandler::processUpdate(DNSPacket& p) {
714 if (! ::arg().mustDo("dnsupdate"))
715 return RCode::Refused;
716
717 string msgPrefix="UPDATE (" + itoa(p.d.id) + ") from " + p.getRemote().toString() + " for " + p.qdomain.toLogString() + ": ";
718 g_log<<Logger::Info<<msgPrefix<<"Processing started."<<endl;
719
720 // if there is policy, we delegate all checks to it
721 if (this->d_update_policy_lua == NULL) {
722
723 // Check permissions - IP based
724 vector<string> allowedRanges;
725 B.getDomainMetadata(p.qdomain, "ALLOW-DNSUPDATE-FROM", allowedRanges);
726 if (! ::arg()["allow-dnsupdate-from"].empty())
727 stringtok(allowedRanges, ::arg()["allow-dnsupdate-from"], ", \t" );
728
729 NetmaskGroup ng;
730 for(const auto& i: allowedRanges) {
731 ng.addMask(i);
732 }
733
734 if ( ! ng.match(&p.d_remote)) {
735 g_log<<Logger::Error<<msgPrefix<<"Remote not listed in allow-dnsupdate-from or domainmetadata. Sending REFUSED"<<endl;
736 return RCode::Refused;
737 }
738
739
740 // Check permissions - TSIG based.
741 vector<string> tsigKeys;
742 B.getDomainMetadata(p.qdomain, "TSIG-ALLOW-DNSUPDATE", tsigKeys);
743 if (tsigKeys.size() > 0) {
744 bool validKey = false;
745
746 TSIGRecordContent trc;
747 DNSName inputkey;
748 string message;
749 if (! p.getTSIGDetails(&trc, &inputkey)) {
750 g_log<<Logger::Error<<msgPrefix<<"TSIG key required, but packet does not contain key. Sending REFUSED"<<endl;
751 return RCode::Refused;
752 }
753
754 if (p.d_tsig_algo == TSIG_GSS) {
755 GssName inputname(p.d_peer_principal); // match against principal since GSS
756 for(const auto& key: tsigKeys) {
757 if (inputname.match(key)) {
758 validKey = true;
759 break;
760 }
761 }
762 } else {
763 for(const auto& key: tsigKeys) {
764 if (inputkey == DNSName(key)) { // because checkForCorrectTSIG has already been performed earlier on, if the names of the ky match with the domain given. THis is valid.
765 validKey=true;
766 break;
767 }
768 }
769 }
770
771 if (!validKey) {
772 g_log<<Logger::Error<<msgPrefix<<"TSIG key ("<<inputkey<<") required, but no matching key found in domainmetadata, tried "<<tsigKeys.size()<<". Sending REFUSED"<<endl;
773 return RCode::Refused;
774 }
775 }
776
777 if (tsigKeys.size() == 0 && p.d_havetsig)
778 g_log<<Logger::Warning<<msgPrefix<<"TSIG is provided, but domain is not secured with TSIG. Processing continues"<<endl;
779
780 }
781
782 // RFC2136 uses the same DNS Header and Message as defined in RFC1035.
783 // This means we can use the MOADNSParser to parse the incoming packet. The result is that we have some different
784 // variable names during the use of our MOADNSParser.
785 MOADNSParser mdp(false, p.getString());
786 if (mdp.d_header.qdcount != 1) {
787 g_log<<Logger::Warning<<msgPrefix<<"Zone Count is not 1, sending FormErr"<<endl;
788 return RCode::FormErr;
789 }
790
791 if (p.qtype.getCode() != QType::SOA) { // RFC2136 2.3 - ZTYPE must be SOA
792 g_log<<Logger::Warning<<msgPrefix<<"Query ZTYPE is not SOA, sending FormErr"<<endl;
793 return RCode::FormErr;
794 }
795
796 if (p.qclass != QClass::IN) {
797 g_log<<Logger::Warning<<msgPrefix<<"Class is not IN, sending NotAuth"<<endl;
798 return RCode::NotAuth;
799 }
800
801 DomainInfo di;
802 di.backend=0;
803 if(!B.getDomainInfo(p.qdomain, di) || !di.backend) {
804 g_log<<Logger::Error<<msgPrefix<<"Can't determine backend for domain '"<<p.qdomain<<"' (or backend does not support DNS update operation)"<<endl;
805 return RCode::NotAuth;
806 }
807
808 if (di.kind == DomainInfo::Slave)
809 return forwardPacket(msgPrefix, p, di);
810
811 // Check if all the records provided are within the zone
812 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
813 const DNSRecord *rr = &i->first;
814 // Skip this check for other field types (like the TSIG - which is in the additional section)
815 // For a TSIG, the label is the dnskey, so it does not pass the endOn validation.
816 if (! (rr->d_place == DNSResourceRecord::ANSWER || rr->d_place == DNSResourceRecord::AUTHORITY))
817 continue;
818
819 if (!rr->d_name.isPartOf(di.zone)) {
820 g_log<<Logger::Error<<msgPrefix<<"Received update/record out of zone, sending NotZone."<<endl;
821 return RCode::NotZone;
822 }
823 }
824
825
826 std::lock_guard<std::mutex> l(s_rfc2136lock); //TODO: i think this lock can be per zone, not for everything
827 g_log<<Logger::Info<<msgPrefix<<"starting transaction."<<endl;
828 if (!di.backend->startTransaction(p.qdomain, -1)) { // Not giving the domain_id means that we do not delete the existing records.
829 g_log<<Logger::Error<<msgPrefix<<"Backend for domain "<<p.qdomain<<" does not support transaction. Can't do Update packet."<<endl;
830 return RCode::NotImp;
831 }
832
833 // 3.2.1 and 3.2.2 - Prerequisite check
834 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
835 const DNSRecord *rr = &i->first;
836 if (rr->d_place == DNSResourceRecord::ANSWER) {
837 int res = checkUpdatePrerequisites(rr, &di);
838 if (res>0) {
839 g_log<<Logger::Error<<msgPrefix<<"Failed PreRequisites check for "<<rr->d_name.toLogString()<<", returning "<<RCode::to_s(res)<<endl;
840 di.backend->abortTransaction();
841 return res;
842 }
843 }
844 }
845
846 // 3.2.3 - Prerequisite check - this is outside of updatePrerequisitesCheck because we check an RRSet and not the RR.
847 typedef pair<DNSName, QType> rrSetKey_t;
848 typedef vector<DNSResourceRecord> rrVector_t;
849 typedef std::map<rrSetKey_t, rrVector_t> RRsetMap_t;
850 RRsetMap_t preReqRRsets;
851 for(const auto& i: mdp.d_answers) {
852 const DNSRecord* rr = &i.first;
853 if (rr->d_place == DNSResourceRecord::ANSWER) {
854 // Last line of 3.2.3
855 if (rr->d_class != QClass::IN && rr->d_class != QClass::NONE && rr->d_class != QClass::ANY)
856 return RCode::FormErr;
857
858 if (rr->d_class == QClass::IN) {
859 rrSetKey_t key = make_pair(rr->d_name, QType(rr->d_type));
860 rrVector_t *vec = &preReqRRsets[key];
861 vec->push_back(DNSResourceRecord::fromWire(*rr));
862 }
863 }
864 }
865
866 if (preReqRRsets.size() > 0) {
867 RRsetMap_t zoneRRsets;
868 for (RRsetMap_t::iterator preRRSet = preReqRRsets.begin(); preRRSet != preReqRRsets.end(); ++preRRSet) {
869 rrSetKey_t rrSet=preRRSet->first;
870 rrVector_t *vec = &preRRSet->second;
871
872 DNSResourceRecord rec;
873 di.backend->lookup(QType(QType::ANY), rrSet.first, di.id);
874 uint16_t foundRR=0, matchRR=0;
875 while (di.backend->get(rec)) {
876 if (rec.qtype == rrSet.second) {
877 foundRR++;
878 for(rrVector_t::iterator rrItem=vec->begin(); rrItem != vec->end(); ++rrItem) {
879 rrItem->ttl = rec.ttl; // The compare one line below also compares TTL, so we make them equal because TTL is not user within prerequisite checks.
880 if (*rrItem == rec)
881 matchRR++;
882 }
883 }
884 }
885 if (matchRR != foundRR || foundRR != vec->size()) {
886 g_log<<Logger::Error<<msgPrefix<<"Failed PreRequisites check (RRs differ), returning NXRRSet"<<endl;
887 di.backend->abortTransaction();
888 return RCode::NXRRSet;
889 }
890 }
891 }
892
893
894
895 // 3.4 - Prescan & Add/Update/Delete records - is all done within a try block.
896 try {
897 uint changedRecords = 0;
898 // 3.4.1 - Prescan section
899 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
900 const DNSRecord *rr = &i->first;
901 if (rr->d_place == DNSResourceRecord::AUTHORITY) {
902 int res = checkUpdatePrescan(rr);
903 if (res>0) {
904 g_log<<Logger::Error<<msgPrefix<<"Failed prescan check, returning "<<res<<endl;
905 di.backend->abortTransaction();
906 return res;
907 }
908 }
909 }
910
911 bool updatedSerial=false;
912 NSEC3PARAMRecordContent ns3pr;
913 bool narrow=false;
914 bool haveNSEC3 = d_dk.getNSEC3PARAM(di.zone, &ns3pr, &narrow);
915 bool isPresigned = d_dk.isPresigned(di.zone);
916
917 // 3.4.2 - Perform the updates.
918 // There's a special condition where deleting the last NS record at zone apex is never deleted (3.4.2.4)
919 // This means we must do it outside the normal performUpdate() because that focusses only on a separate RR.
920 vector<const DNSRecord *> nsRRtoDelete;
921
922 // Another special case is the addition of both a CNAME and a non-CNAME for the same name (#6270)
923 set<DNSName> cn, nocn;
924 for (const auto &rr : mdp.d_answers) {
925 if (rr.first.d_place == DNSResourceRecord::AUTHORITY && rr.first.d_class == QClass::IN && rr.first.d_ttl > 0) {
926 // Addition
927 if (rr.first.d_type == QType::CNAME) {
928 cn.insert(rr.first.d_name);
929 } else if (rr.first.d_type != QType::RRSIG) {
930 nocn.insert(rr.first.d_name);
931 }
932 }
933 }
934 for (auto const &n : cn) {
935 if (nocn.count(n) > 0) {
936 g_log<<Logger::Error<<msgPrefix<<"Refusing update, found CNAME and non-CNAME addition"<<endl;
937 di.backend->abortTransaction();
938 return RCode::FormErr;
939 }
940 }
941
942 vector<const DNSRecord *> cnamesToAdd, nonCnamesToAdd;
943 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
944 const DNSRecord *rr = &i->first;
945 if (rr->d_place == DNSResourceRecord::AUTHORITY) {
946 /* see if it's permitted by policy */
947 if (this->d_update_policy_lua != NULL) {
948 if (this->d_update_policy_lua->updatePolicy(rr->d_name, QType(rr->d_type), di.zone, p) == false) {
949 g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).getName() << ": Not permitted by policy"<<endl;
950 continue;
951 } else {
952 g_log<<Logger::Debug<<msgPrefix<<"Accepting update for " << rr->d_name << "/" << QType(rr->d_type).getName() << ": Permitted by policy"<<endl;
953 }
954 }
955
956 if (rr->d_class == QClass::NONE && rr->d_type == QType::NS && rr->d_name == di.zone)
957 nsRRtoDelete.push_back(rr);
958 else if (rr->d_class == QClass::IN && rr->d_ttl > 0) {
959 if (rr->d_type == QType::CNAME) {
960 cnamesToAdd.push_back(rr);
961 } else {
962 nonCnamesToAdd.push_back(rr);
963 }
964 }
965 else
966 changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
967 }
968 }
969 for (const auto &rr : cnamesToAdd) {
970 DNSResourceRecord rec;
971 di.backend->lookup(QType(QType::ANY), rr->d_name, di.id);
972 while (di.backend->get(rec)) {
973 if (rec.qtype != QType::CNAME && rec.qtype != QType::ENT && rec.qtype != QType::RRSIG) {
974 // leave database handle in a consistent state
975 while (di.backend->get(rec))
976 ;
977 g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).getName() << ": Data other than CNAME exists for the same name"<<endl;
978 di.backend->abortTransaction();
979 return RCode::Refused;
980 }
981 }
982 changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
983 }
984 for (const auto &rr : nonCnamesToAdd) {
985 DNSResourceRecord rec;
986 di.backend->lookup(QType(QType::CNAME), rr->d_name, di.id);
987 while (di.backend->get(rec)) {
988 if (rec.qtype == QType::CNAME && rr->d_type != QType::RRSIG) {
989 // leave database handle in a consistent state
990 while (di.backend->get(rec))
991 ;
992 g_log<<Logger::Warning<<msgPrefix<<"Refusing update for " << rr->d_name << "/" << QType(rr->d_type).getName() << ": CNAME exists for the same name"<<endl;
993 di.backend->abortTransaction();
994 return RCode::Refused;
995 }
996 }
997 changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
998 }
999 if (nsRRtoDelete.size()) {
1000 vector<DNSResourceRecord> nsRRInZone;
1001 DNSResourceRecord rec;
1002 di.backend->lookup(QType(QType::NS), di.zone, di.id);
1003 while (di.backend->get(rec)) {
1004 nsRRInZone.push_back(rec);
1005 }
1006 if (nsRRInZone.size() > nsRRtoDelete.size()) { // only delete if the NS's we delete are less then what we have in the zone (3.4.2.4)
1007 for (auto& inZone: nsRRInZone) {
1008 for (auto& rr: nsRRtoDelete) {
1009 if (inZone.getZoneRepresentation() == (rr)->d_content->getZoneRepresentation())
1010 changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
1011 }
1012 }
1013 }
1014 }
1015
1016 // Section 3.6 - Update the SOA serial - outside of performUpdate because we do a SOA update for the complete update message
1017 if (changedRecords > 0 && !updatedSerial) {
1018 increaseSerial(msgPrefix, &di, haveNSEC3, narrow, &ns3pr);
1019 changedRecords++;
1020 }
1021
1022 if (changedRecords > 0) {
1023 if (!di.backend->commitTransaction()) {
1024 g_log<<Logger::Error<<msgPrefix<<"Failed to commit updates!"<<endl;
1025 return RCode::ServFail;
1026 }
1027
1028 S.deposit("dnsupdate-changes", changedRecords);
1029
1030 // Purge the records!
1031 string zone(di.zone.toString());
1032 zone.append("$");
1033 purgeAuthCaches(zone);
1034
1035 // Notify slaves
1036 if (di.kind == DomainInfo::Master) {
1037 vector<string> notify;
1038 B.getDomainMetadata(p.qdomain, "NOTIFY-DNSUPDATE", notify);
1039 if (!notify.empty() && notify.front() == "1") {
1040 Communicator.notifyDomain(di.zone, &B);
1041 }
1042 }
1043
1044 g_log<<Logger::Info<<msgPrefix<<"Update completed, "<<changedRecords<<" changed records committed."<<endl;
1045 } else {
1046 //No change, no commit, we perform abort() because some backends might like this more.
1047 g_log<<Logger::Info<<msgPrefix<<"Update completed, 0 changes, rolling back."<<endl;
1048 di.backend->abortTransaction();
1049 }
1050 return RCode::NoError; //rfc 2136 3.4.2.5
1051 }
1052 catch (SSqlException &e) {
1053 g_log<<Logger::Error<<msgPrefix<<"Caught SSqlException: "<<e.txtReason()<<"; Sending ServFail!"<<endl;
1054 di.backend->abortTransaction();
1055 return RCode::ServFail;
1056 }
1057 catch (DBException &e) {
1058 g_log<<Logger::Error<<msgPrefix<<"Caught DBException: "<<e.reason<<"; Sending ServFail!"<<endl;
1059 di.backend->abortTransaction();
1060 return RCode::ServFail;
1061 }
1062 catch (PDNSException &e) {
1063 g_log<<Logger::Error<<msgPrefix<<"Caught PDNSException: "<<e.reason<<"; Sending ServFail!"<<endl;
1064 di.backend->abortTransaction();
1065 return RCode::ServFail;
1066 }
1067 catch(std::exception &e) {
1068 g_log<<Logger::Error<<msgPrefix<<"Caught std:exception: "<<e.what()<<"; Sending ServFail!"<<endl;
1069 di.backend->abortTransaction();
1070 return RCode::ServFail;
1071 }
1072 catch (...) {
1073 g_log<<Logger::Error<<msgPrefix<<"Caught unknown exception when performing update. Sending ServFail!"<<endl;
1074 di.backend->abortTransaction();
1075 return RCode::ServFail;
1076 }
1077 }
1078
1079 void PacketHandler::increaseSerial(const string &msgPrefix, const DomainInfo *di, bool haveNSEC3, bool narrow, const NSEC3PARAMRecordContent *ns3pr) {
1080 SOAData sd;
1081 if (!di->backend->getSOA(di->zone, sd)) {
1082 throw PDNSException("SOA-Serial update failed because there was no SOA. Wowie.");
1083 }
1084
1085 uint32_t oldSerial = sd.serial;
1086
1087 vector<string> soaEdit2136Setting;
1088 B.getDomainMetadata(di->zone, "SOA-EDIT-DNSUPDATE", soaEdit2136Setting);
1089 string soaEdit2136 = "DEFAULT";
1090 string soaEdit;
1091 if (!soaEdit2136Setting.empty()) {
1092 soaEdit2136 = soaEdit2136Setting[0];
1093 if (pdns_iequals(soaEdit2136, "SOA-EDIT") || pdns_iequals(soaEdit2136,"SOA-EDIT-INCREASE") ){
1094 string soaEditSetting;
1095 d_dk.getSoaEdit(di->zone, soaEditSetting);
1096 if (soaEditSetting.empty()) {
1097 g_log<<Logger::Error<<msgPrefix<<"Using "<<soaEdit2136<<" for SOA-EDIT-DNSUPDATE increase on DNS update, but SOA-EDIT is not set for domain \""<< di->zone.toLogString() <<"\". Using DEFAULT for SOA-EDIT-DNSUPDATE"<<endl;
1098 soaEdit2136 = "DEFAULT";
1099 } else
1100 soaEdit = soaEditSetting;
1101 }
1102 }
1103
1104 DNSResourceRecord rr;
1105 if (makeIncreasedSOARecord(sd, soaEdit2136, soaEdit, rr)) {
1106 di->backend->replaceRRSet(di->id, rr.qname, rr.qtype, vector<DNSResourceRecord>(1, rr));
1107 g_log << Logger::Notice << msgPrefix << "Increasing SOA serial (" << oldSerial << " -> " << sd.serial << ")" << endl;
1108
1109 //Correct ordername + auth flag
1110 if (haveNSEC3) {
1111 DNSName ordername;
1112 if (!narrow)
1113 ordername = DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, rr.qname)));
1114
1115 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr.qname, ordername, true);
1116 } else { // NSEC
1117 DNSName ordername = rr.qname.makeRelative(di->zone);
1118 di->backend->updateDNSSECOrderNameAndAuth(di->id, rr.qname, ordername, true);
1119 }
1120 }
1121 }