]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/rpzloader.cc
Merge pull request #7689 from rgacogne/dnsdist-14-packetcache
[thirdparty/pdns.git] / pdns / rpzloader.cc
CommitLineData
644dd1da 1#include "dnsparser.hh"
2#include "dnsrecords.hh"
4ba9d5dc 3#include "ixfr.hh"
644dd1da 4#include "syncres.hh"
39ec5d29 5#include "resolver.hh"
6#include "logger.hh"
ad42489c 7#include "rec-lua-conf.hh"
4ba9d5dc
RG
8#include "rpzloader.hh"
9#include "zoneparser-tng.hh"
519f5484 10#include "threadname.hh"
644dd1da 11
12static Netmask makeNetmaskFromRPZ(const DNSName& name)
13{
14 auto parts = name.getRawLabels();
b8470add
PL
15 /*
16 * why 2?, the minimally valid IPv6 address that can be encoded in an RPZ is
17 * $NETMASK.zz (::/$NETMASK)
18 * Terrible right?
19 */
20 if(parts.size() < 2 || parts.size() > 9)
86f1af1c 21 throw PDNSException("Invalid IP address in RPZ: "+name.toLogString());
b8470add
PL
22
23 bool isV6 = (stoi(parts[0]) > 32);
24 bool hadZZ = false;
25
26 for (auto &part : parts) {
27 // Check if we have an IPv4 octet
28 for (auto c : part)
29 if (!isdigit(c))
30 isV6 = true;
31
32 if (pdns_iequals(part,"zz")) {
33 if (hadZZ)
86f1af1c 34 throw PDNSException("more than one 'zz' label found in RPZ name"+name.toLogString());
b8470add
PL
35 part = "";
36 isV6 = true;
37 hadZZ = true;
38 }
39 }
40
41 if (isV6 && parts.size() < 9 && !hadZZ)
86f1af1c 42 throw PDNSException("No 'zz' label found in an IPv6 RPZ name shorter than 9 elements: "+name.toLogString());
b8470add
PL
43
44 if (parts.size() == 5 && !isV6)
45 return Netmask(parts[4]+"."+parts[3]+"."+parts[2]+"."+parts[1]+"/"+parts[0]);
46
47 string v6;
48
49 for (uint8_t i = parts.size()-1 ; i > 0; i--) {
50 v6 += parts[i];
51 if (parts[i] == "" && i == 1 && i == parts.size()-1)
52 v6+= "::";
53 if (parts[i] == "" && i != parts.size()-1)
54 v6+= ":";
55 if (parts[i] != "" && i != 1)
56 v6 += ":";
57 }
58 v6 += "/" + parts[0];
59
60 return Netmask(v6);
644dd1da 61}
62
d122dac0 63static void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr<DNSFilterEngine::Zone> zone, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, bool defpolOverrideLocal, uint32_t maxTTL)
644dd1da 64{
644dd1da 65 static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru.");
644dd1da 66 static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"),
67 rpzNSDname("rpz-nsdname"), rpzNSIP("rpz-nsip.");
39c9bef5 68 static const std::string rpzPrefix("rpz-");
39ec5d29 69
1f1ca368 70 DNSFilterEngine::Policy pol;
d122dac0 71 bool defpolApplied = false;
39ec5d29 72
ba3c54cb
RG
73 if(dr.d_class != QClass::IN) {
74 return;
75 }
76
39ec5d29 77 if(dr.d_type == QType::CNAME) {
ba3c54cb
RG
78 auto crc = getRR<CNAMERecordContent>(dr);
79 if (!crc) {
80 return;
81 }
dd079764 82 auto crcTarget=crc->getTarget();
ad42489c 83 if(defpol) {
84 pol=*defpol;
d122dac0 85 defpolApplied = true;
ad42489c 86 }
dd079764 87 else if(crcTarget.isRoot()) {
39ec5d29 88 // cerr<<"Wants NXDOMAIN for "<<dr.d_name<<": ";
89 pol.d_kind = DNSFilterEngine::PolicyKind::NXDOMAIN;
dd079764 90 } else if(crcTarget==g_wildcarddnsname) {
39ec5d29 91 // cerr<<"Wants NODATA for "<<dr.d_name<<": ";
92 pol.d_kind = DNSFilterEngine::PolicyKind::NODATA;
93 }
dd079764 94 else if(crcTarget==drop) {
39ec5d29 95 // cerr<<"Wants DROP for "<<dr.d_name<<": ";
96 pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
97 }
dd079764 98 else if(crcTarget==truncate) {
39ec5d29 99 // cerr<<"Wants TRUNCATE for "<<dr.d_name<<": ";
100 pol.d_kind = DNSFilterEngine::PolicyKind::Truncate;
101 }
dd079764 102 else if(crcTarget==noaction) {
39ec5d29 103 // cerr<<"Wants NOACTION for "<<dr.d_name<<": ";
104 pol.d_kind = DNSFilterEngine::PolicyKind::NoAction;
105 }
39c9bef5
RG
106 /* "The special RPZ encodings which are not to be taken as Local Data are
107 CNAMEs with targets that are:
108 + "." (NXDOMAIN action),
109 + "*." (NODATA action),
110 + a top level domain starting with "rpz-",
111 + a child of a top level domain starting with "rpz-".
112 */
113 else if(!crcTarget.empty() && !crcTarget.isRoot() && crcTarget.getRawLabel(crcTarget.countLabels() - 1).compare(0, rpzPrefix.length(), rpzPrefix) == 0) {
114 /* this is very likely an higher format number or a configuration error,
115 let's just ignore it. */
e6a9dde5 116 g_log<<Logger::Info<<"Discarding unsupported RPZ entry "<<crcTarget<<" for "<<dr.d_name<<endl;
39c9bef5
RG
117 return;
118 }
39ec5d29 119 else {
120 pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
6da513b2 121 pol.d_custom.emplace_back(dr.d_content);
dd079764 122 // cerr<<"Wants custom "<<crcTarget<<" for "<<dr.d_name<<": ";
39ec5d29 123 }
124 }
125 else {
d122dac0 126 if (defpol && defpolOverrideLocal) {
db7dcbb1 127 pol=*defpol;
d122dac0 128 defpolApplied = true;
db7dcbb1
RG
129 }
130 else {
131 pol.d_kind = DNSFilterEngine::PolicyKind::Custom;
6da513b2 132 pol.d_custom.emplace_back(dr.d_content);
db7dcbb1
RG
133 // cerr<<"Wants custom "<<dr.d_content->getZoneRepresentation()<<" for "<<dr.d_name<<": ";
134 }
39ec5d29 135 }
136
d122dac0 137 if (!defpolApplied || defpol->d_ttl < 0) {
8f618901
RG
138 pol.d_ttl = static_cast<int32_t>(std::min(maxTTL, dr.d_ttl));
139 } else {
140 pol.d_ttl = static_cast<int32_t>(std::min(maxTTL, static_cast<uint32_t>(pol.d_ttl)));
141 }
3876ee44 142
39ec5d29 143 // now to DO something with that
39c9bef5 144
39ec5d29 145 if(dr.d_name.isPartOf(rpzNSDname)) {
146 DNSName filt=dr.d_name.makeRelative(rpzNSDname);
147 if(addOrRemove)
6da513b2 148 zone->addNSTrigger(filt, std::move(pol));
39ec5d29 149 else
6da513b2 150 zone->rmNSTrigger(filt, std::move(pol));
6791663c 151 } else if(dr.d_name.isPartOf(rpzClientIP)) {
b8470add
PL
152 DNSName filt=dr.d_name.makeRelative(rpzClientIP);
153 auto nm=makeNetmaskFromRPZ(filt);
39ec5d29 154 if(addOrRemove)
6da513b2 155 zone->addClientTrigger(nm, std::move(pol));
39ec5d29 156 else
6da513b2 157 zone->rmClientTrigger(nm, std::move(pol));
39ec5d29 158
6791663c 159 } else if(dr.d_name.isPartOf(rpzIP)) {
39ec5d29 160 // cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
b8470add
PL
161 DNSName filt=dr.d_name.makeRelative(rpzIP);
162 auto nm=makeNetmaskFromRPZ(filt);
39ec5d29 163 if(addOrRemove)
6da513b2 164 zone->addResponseTrigger(nm, std::move(pol));
39ec5d29 165 else
6da513b2 166 zone->rmResponseTrigger(nm, std::move(pol));
39ec5d29 167 } else if(dr.d_name.isPartOf(rpzNSIP)) {
b8470add
PL
168 DNSName filt=dr.d_name.makeRelative(rpzNSIP);
169 auto nm=makeNetmaskFromRPZ(filt);
170 if(addOrRemove)
6da513b2 171 zone->addNSIPTrigger(nm, std::move(pol));
b8470add 172 else
6da513b2 173 zone->rmNSIPTrigger(nm, std::move(pol));
39ec5d29 174 } else {
d122dac0
RG
175 if(addOrRemove) {
176 /* if we did override the existing policy with the default policy,
177 we might turn two A or AAAA into a CNAME, which would trigger
178 an exception. Let's just ignore it. */
179 zone->addQNameTrigger(dr.d_name, std::move(pol), defpolApplied);
180 }
181 else {
6da513b2 182 zone->rmQNameTrigger(dr.d_name, std::move(pol));
d122dac0 183 }
39ec5d29 184 }
185}
186
d122dac0 187static shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, bool defpolOverrideLocal, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, uint16_t axfrTimeout)
39ec5d29 188{
e6a9dde5 189 g_log<<Logger::Warning<<"Loading RPZ zone '"<<zoneName<<"' from "<<master.toStringWithPort()<<endl;
98c9ec39 190 if(!tt.name.empty())
e6a9dde5 191 g_log<<Logger::Warning<<"With TSIG key '"<<tt.name<<"' of algorithm '"<<tt.algo<<"'"<<endl;
98c9ec39 192
f6a8f7d7
PL
193 ComboAddress local(localAddress);
194 if (local == ComboAddress())
195 local = getQueryLocalAddress(master.sin4.sin_family, 0);
196
e07c3801 197 AXFRRetriever axfr(master, zoneName, tt, &local, maxReceivedBytes, axfrTimeout);
39ec5d29 198 unsigned int nrecords=0;
199 Resolver::res_t nop;
200 vector<DNSRecord> chunk;
201 time_t last=0;
cb6218d2
PL
202 time_t axfrStart = time(nullptr);
203 time_t axfrNow = time(nullptr);
39ec5d29 204 shared_ptr<SOARecordContent> sr;
ea448a77 205 while(axfr.getChunk(nop, &chunk, (axfrStart + axfrTimeout - axfrNow))) {
39ec5d29 206 for(auto& dr : chunk) {
98c9ec39 207 if(dr.d_type==QType::NS || dr.d_type==QType::TSIG) {
208 continue;
209 }
210
6b972d59 211 dr.d_name.makeUsRelative(zoneName);
39ec5d29 212 if(dr.d_type==QType::SOA) {
ba3c54cb 213 sr = getRR<SOARecordContent>(dr);
39ec5d29 214 continue;
215 }
39ec5d29 216
d122dac0 217 RPZRecordToPolicy(dr, zone, true, defpol, defpolOverrideLocal, maxTTL);
39ec5d29 218 nrecords++;
219 }
ea448a77 220 axfrNow = time(nullptr);
cb6218d2 221 if (axfrNow < axfrStart || axfrNow - axfrStart > axfrTimeout) {
ea448a77
PL
222 throw PDNSException("Total AXFR time exceeded!");
223 }
39ec5d29 224 if(last != time(0)) {
210ae1af 225 g_log<<Logger::Info<<"Loaded & indexed "<<nrecords<<" policy records so far for RPZ zone '"<<zoneName<<"'"<<endl;
39ec5d29 226 last=time(0);
227 }
228 }
e6a9dde5 229 g_log<<Logger::Info<<"Done: "<<nrecords<<" policy records active, SOA: "<<sr->getZoneRepresentation()<<endl;
39ec5d29 230 return sr;
231}
232
c823f860 233// this function is silent - you do the logging
d122dac0 234std::shared_ptr<SOARecordContent> loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, bool defpolOverrideLocal, uint32_t maxTTL)
39ec5d29 235{
a66c5cfa 236 shared_ptr<SOARecordContent> sr = nullptr;
39ec5d29 237 ZoneParserTNG zpt(fname);
238 DNSResourceRecord drr;
644dd1da 239 DNSName domain;
240 while(zpt.get(drr)) {
644dd1da 241 try {
242 if(drr.qtype.getCode() == QType::CNAME && drr.content.empty())
243 drr.content=".";
244 DNSRecord dr(drr);
245 if(dr.d_type == QType::SOA) {
a66c5cfa 246 sr = getRR<SOARecordContent>(dr);
6791663c
RG
247 domain = dr.d_name;
248 zone->setDomain(domain);
644dd1da 249 }
39ec5d29 250 else if(dr.d_type == QType::NS) {
251 continue;
252 }
253 else {
644dd1da 254 dr.d_name=dr.d_name.makeRelative(domain);
d122dac0 255 RPZRecordToPolicy(dr, zone, true, defpol, defpolOverrideLocal, maxTTL);
644dd1da 256 }
257 }
6791663c 258 catch(const PDNSException& pe) {
86f1af1c 259 throw PDNSException("Issue parsing '"+drr.qname.toLogString()+"' '"+drr.content+"' at "+zpt.getLineOfFile()+": "+pe.reason);
644dd1da 260 }
261 }
a66c5cfa
RG
262
263 return sr;
644dd1da 264}
4ba9d5dc 265
20c37dec 266static std::unordered_map<std::string, shared_ptr<rpzStats> > s_rpzStats;
4ba9d5dc
RG
267static std::mutex s_rpzStatsMutex;
268
20c37dec 269shared_ptr<rpzStats> getRPZZoneStats(const std::string& zone)
4ba9d5dc
RG
270{
271 std::lock_guard<std::mutex> l(s_rpzStatsMutex);
20c37dec
PL
272 if (s_rpzStats.find(zone) == s_rpzStats.end()) {
273 s_rpzStats[zone] = std::make_shared<rpzStats>();
274 }
4ba9d5dc
RG
275 return s_rpzStats[zone];
276}
277
278static void incRPZFailedTransfers(const std::string& zone)
279{
20c37dec
PL
280 auto stats = getRPZZoneStats(zone);
281 if (stats != nullptr)
282 stats->d_failedTransfers++;
4ba9d5dc
RG
283}
284
285static void setRPZZoneNewState(const std::string& zone, uint32_t serial, uint64_t numberOfRecords, bool wasAXFR)
286{
20c37dec
PL
287 auto stats = getRPZZoneStats(zone);
288 if (stats == nullptr)
289 return;
290 stats->d_successfulTransfers++;
4ba9d5dc 291 if (wasAXFR) {
20c37dec 292 stats->d_fullTransfers++;
4ba9d5dc 293 }
20c37dec
PL
294 stats->d_lastUpdate = time(nullptr);
295 stats->d_serial = serial;
296 stats->d_numberOfRecords = numberOfRecords;
4ba9d5dc
RG
297}
298
23f886c0
RG
299static bool dumpZoneToDisk(const DNSName& zoneName, const std::shared_ptr<DNSFilterEngine::Zone>& newZone, const std::string& dumpZoneFileName)
300{
301 std::string temp = dumpZoneFileName + "XXXXXX";
302 int fd = mkstemp(&temp.at(0));
303 if (fd < 0) {
304 g_log<<Logger::Warning<<"Unable to open a file to dump the content of the RPZ zone "<<zoneName.toLogString()<<endl;
305 return false;
306 }
307
5e1f23ca
RG
308 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(fd, "w+"), fclose);
309 if (!fp) {
23f886c0
RG
310 close(fd);
311 g_log<<Logger::Warning<<"Unable to open a file pointer to dump the content of the RPZ zone "<<zoneName.toLogString()<<endl;
312 return false;
313 }
23f886c0
RG
314 fd = -1;
315
316 try {
5e1f23ca 317 newZone->dump(fp.get());
23f886c0
RG
318 }
319 catch(const std::exception& e) {
320 g_log<<Logger::Warning<<"Error while dumping the content of the RPZ zone "<<zoneName.toLogString()<<": "<<e.what()<<endl;
23f886c0
RG
321 return false;
322 }
323
5e1f23ca 324 if (fflush(fp.get()) != 0) {
23f886c0
RG
325 g_log<<Logger::Warning<<"Error while flushing the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
326 return false;
327 }
328
5e1f23ca 329 if (fsync(fileno(fp.get())) != 0) {
23f886c0
RG
330 g_log<<Logger::Warning<<"Error while syncing the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
331 return false;
332 }
333
5e1f23ca 334 if (fclose(fp.release()) != 0) {
23f886c0
RG
335 g_log<<Logger::Warning<<"Error while writing the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
336 return false;
337 }
338
339 if (rename(temp.c_str(), dumpZoneFileName.c_str()) != 0) {
340 g_log<<Logger::Warning<<"Error while moving the content of the RPZ zone "<<zoneName.toLogString()<<" to the dump file: "<<strerror(errno)<<endl;
341 return false;
342 }
343
344 return true;
345}
346
d122dac0 347void RPZIXFRTracker(const std::vector<ComboAddress>& masters, boost::optional<DNSFilterEngine::Policy> defpol, bool defpolOverrideLocal, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress, const uint16_t axfrTimeout, std::shared_ptr<SOARecordContent> sr, std::string dumpZoneFileName, uint64_t configGeneration)
4ba9d5dc 348{
519f5484 349 setThreadName("pdns-r/RPZIXFR");
a66c5cfa 350 bool isPreloaded = sr != nullptr;
1bf8d12a
RG
351 auto luaconfsLocal = g_luaconfs.getLocal();
352 /* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */
353 std::shared_ptr<DNSFilterEngine::Zone> oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
354 if (!oldZone) {
355 g_log<<Logger::Error<<"Unable to retrieve RPZ zone with index "<<zoneIdx<<" from the configuration, exiting"<<endl;
356 return;
357 }
358 uint32_t refresh = oldZone->getRefresh();
359 DNSName zoneName = oldZone->getDomain();
360 std::string polName = oldZone->getName() ? *(oldZone->getName()) : zoneName.toString();
4ba9d5dc
RG
361
362 while (!sr) {
a66c5cfa
RG
363 /* if we received an empty sr, the zone was not really preloaded */
364
1bf8d12a
RG
365 /* full copy, as promised */
366 std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
5f311886
RG
367 for (const auto& master : masters) {
368 try {
d122dac0 369 sr = loadRPZFromServer(master, zoneName, newZone, defpol, defpolOverrideLocal, maxTTL, tt, maxReceivedBytes, localAddress, axfrTimeout);
5f311886
RG
370 if(refresh == 0) {
371 refresh = sr->d_st.refresh;
372 }
373 newZone->setSerial(sr->d_st.serial);
374 setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), true);
375
376 g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
377 lci.dfe.setZone(zoneIdx, newZone);
378 });
379
380 if (!dumpZoneFileName.empty()) {
381 dumpZoneToDisk(zoneName, newZone, dumpZoneFileName);
382 }
383
384 /* no need to try another master */
385 break;
4ba9d5dc 386 }
5f311886
RG
387 catch(const std::exception& e) {
388 g_log<<Logger::Warning<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master<<"': '"<<e.what()<<"'. (Will try again in "<<(refresh > 0 ? refresh : 10)<<" seconds...)"<<endl;
389 incRPZFailedTransfers(polName);
390 }
391 catch(const PDNSException& e) {
392 g_log<<Logger::Warning<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master<<"': '"<<e.reason<<"'. (Will try again in "<<(refresh > 0 ? refresh : 10)<<" seconds...)"<<endl;
393 incRPZFailedTransfers(polName);
23f886c0 394 }
4ba9d5dc
RG
395 }
396
397 if (!sr) {
398 if (refresh == 0) {
399 sleep(10);
400 } else {
401 sleep(refresh);
402 }
403 }
404 }
405
a66c5cfa 406 bool skipRefreshDelay = isPreloaded;
13dacc77 407
4ba9d5dc
RG
408 for(;;) {
409 DNSRecord dr;
410 dr.d_content=sr;
411
a66c5cfa
RG
412 if (skipRefreshDelay) {
413 skipRefreshDelay = false;
414 }
415 else {
416 sleep(refresh);
417 }
4ba9d5dc 418
13dacc77
RG
419 if (luaconfsLocal->generation != configGeneration) {
420 /* the configuration has been reloaded, meaning that a new thread
421 has been started to handle that zone and we are now obsolete.
422 */
423 g_log<<Logger::Info<<"A more recent configuration has been found, stopping the existing RPZ update thread for "<<zoneName<<endl;
424 return;
425 }
426
4ba9d5dc 427 vector<pair<vector<DNSRecord>, vector<DNSRecord> > > deltas;
5f311886
RG
428 for (const auto& master : masters) {
429 g_log<<Logger::Info<<"Getting IXFR deltas for "<<zoneName<<" from "<<master.toStringWithPort()<<", our serial: "<<getRR<SOARecordContent>(dr)->d_st.serial<<endl;
430
431 ComboAddress local(localAddress);
432 if (local == ComboAddress()) {
433 local = getQueryLocalAddress(master.sin4.sin_family, 0);
434 }
4ba9d5dc 435
5f311886
RG
436 try {
437 deltas = getIXFRDeltas(master, zoneName, dr, tt, &local, maxReceivedBytes);
4ba9d5dc 438
5f311886
RG
439 /* no need to try another master */
440 break;
441 } catch(const std::runtime_error& e ){
442 g_log<<Logger::Warning<<e.what()<<endl;
443 incRPZFailedTransfers(polName);
444 continue;
445 }
4ba9d5dc 446 }
5f311886
RG
447
448 if(deltas.empty()) {
4ba9d5dc 449 continue;
5f311886
RG
450 }
451
e6a9dde5 452 g_log<<Logger::Info<<"Processing "<<deltas.size()<<" delta"<<addS(deltas)<<" for RPZ "<<zoneName<<endl;
4ba9d5dc 453
1bf8d12a 454 oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
4ba9d5dc
RG
455 /* we need to make a _full copy_ of the zone we are going to work on */
456 std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
457
458 int totremove=0, totadd=0;
459 bool fullUpdate = false;
460 for(const auto& delta : deltas) {
461 const auto& remove = delta.first;
462 const auto& add = delta.second;
463 if(remove.empty()) {
e6a9dde5 464 g_log<<Logger::Warning<<"IXFR update is a whole new zone"<<endl;
4ba9d5dc
RG
465 newZone->clear();
466 fullUpdate = true;
467 }
468 for(const auto& rr : remove) { // should always contain the SOA
469 if(rr.d_type == QType::NS)
470 continue;
471 if(rr.d_type == QType::SOA) {
472 auto oldsr = getRR<SOARecordContent>(rr);
473 if(oldsr && oldsr->d_st.serial == sr->d_st.serial) {
474 // cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
475 }
476 else
e6a9dde5 477 g_log<<Logger::Error<<"GOT WRONG SOA SERIAL REMOVAL, SHOULD TRIGGER WHOLE RELOAD"<<endl;
4ba9d5dc
RG
478 }
479 else {
480 totremove++;
e6a9dde5 481 g_log<<(g_logRPZChanges ? Logger::Info : Logger::Debug)<<"Had removal of "<<rr.d_name<<" from RPZ zone "<<zoneName<<endl;
d122dac0 482 RPZRecordToPolicy(rr, newZone, false, defpol, defpolOverrideLocal, maxTTL);
4ba9d5dc
RG
483 }
484 }
485
486 for(const auto& rr : add) { // should always contain the new SOA
487 if(rr.d_type == QType::NS)
488 continue;
489 if(rr.d_type == QType::SOA) {
490 auto newsr = getRR<SOARecordContent>(rr);
e6a9dde5 491 // g_log<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<newsr->d_st.serial<<endl;
4ba9d5dc
RG
492 if (newsr) {
493 sr = newsr;
494 }
495 }
496 else {
497 totadd++;
e6a9dde5 498 g_log<<(g_logRPZChanges ? Logger::Info : Logger::Debug)<<"Had addition of "<<rr.d_name<<" to RPZ zone "<<zoneName<<endl;
d122dac0 499 RPZRecordToPolicy(rr, newZone, true, defpol, defpolOverrideLocal, maxTTL);
4ba9d5dc
RG
500 }
501 }
502 }
e6a9dde5 503 g_log<<Logger::Info<<"Had "<<totremove<<" RPZ removal"<<addS(totremove)<<", "<<totadd<<" addition"<<addS(totadd)<<" for "<<zoneName<<" New serial: "<<sr->d_st.serial<<endl;
4ba9d5dc
RG
504 newZone->setSerial(sr->d_st.serial);
505 setRPZZoneNewState(polName, sr->d_st.serial, newZone->size(), fullUpdate);
506
507 /* we need to replace the existing zone with the new one,
508 but we don't want to touch anything else, especially other zones,
509 since they might have been updated by another RPZ IXFR tracker thread.
510 */
511 g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
512 lci.dfe.setZone(zoneIdx, newZone);
513 });
23f886c0
RG
514
515 if (!dumpZoneFileName.empty()) {
516 dumpZoneToDisk(zoneName, newZone, dumpZoneFileName);
517 }
4ba9d5dc
RG
518 }
519}