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