]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/rpzloader.cc
1 #include "arguments.hh"
2 #include "dnsparser.hh"
3 #include "dnsrecords.hh"
6 #include "axfr-retriever.hh"
10 #include "rec-lua-conf.hh"
11 #include "rpzloader.hh"
12 #include "zoneparser-tng.hh"
13 #include "threadname.hh"
14 #include "query-local-address.hh"
16 Netmask
makeNetmaskFromRPZ ( const DNSName
& name
)
18 auto parts
= name
. getRawLabels ();
20 * why 2?, the minimally valid IPv6 address that can be encoded in an RPZ is
21 * $NETMASK.zz (::/$NETMASK)
24 if ( parts
. size () < 2 || parts
. size () > 9 )
25 throw PDNSException ( "Invalid IP address in RPZ: " + name
. toLogString ());
27 bool isV6
= ( stoi ( parts
[ 0 ]) > 32 );
30 for ( auto & part
: parts
) {
31 // Check if we have an IPv4 octet
36 if ( pdns_iequals ( part
, "zz" )) {
38 throw PDNSException ( "more than one 'zz' label found in RPZ name" + name
. toLogString ());
45 if ( isV6
&& parts
. size () < 9 && ! hadZZ
)
46 throw PDNSException ( "No 'zz' label found in an IPv6 RPZ name shorter than 9 elements: " + name
. toLogString ());
48 if ( parts
. size () == 5 && ! isV6
)
49 return Netmask ( parts
[ 4 ]+ "." + parts
[ 3 ]+ "." + parts
[ 2 ]+ "." + parts
[ 1 ]+ "/" + parts
[ 0 ]);
53 if ( parts
[ parts
. size ()- 1 ] == "" ) {
56 for ( uint8_t i
= parts
. size ()- 1 ; i
> 0 ; i
--) {
58 if ( i
> 1 || ( i
== 1 && parts
[ i
] == "" )) {
67 static void RPZRecordToPolicy ( const DNSRecord
& dr
, std :: shared_ptr
< DNSFilterEngine :: Zone
> zone
, bool addOrRemove
, const boost :: optional
< DNSFilterEngine :: Policy
>& defpol
, bool defpolOverrideLocal
, uint32_t maxTTL
)
69 static const DNSName
drop ( "rpz-drop." ), truncate ( "rpz-tcp-only." ), noaction ( "rpz-passthru." );
70 static const DNSName
rpzClientIP ( "rpz-client-ip" ), rpzIP ( "rpz-ip" ),
71 rpzNSDname ( "rpz-nsdname" ), rpzNSIP ( "rpz-nsip." );
72 static const std :: string
rpzPrefix ( "rpz-" );
74 DNSFilterEngine :: Policy pol
;
75 bool defpolApplied
= false ;
77 if ( dr
. d_class
!= QClass :: IN
) {
81 if ( dr
. d_type
== QType :: CNAME
) {
82 auto crc
= getRR
< CNAMERecordContent
>( dr
);
86 auto crcTarget
= crc
-> getTarget ();
91 else if ( crcTarget
. isRoot ()) {
92 // cerr<<"Wants NXDOMAIN for "<<dr.d_name<<": ";
93 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: NXDOMAIN
;
94 } else if ( crcTarget
== g_wildcarddnsname
) {
95 // cerr<<"Wants NODATA for "<<dr.d_name<<": ";
96 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: NODATA
;
98 else if ( crcTarget
== drop
) {
99 // cerr<<"Wants DROP for "<<dr.d_name<<": ";
100 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: Drop
;
102 else if ( crcTarget
== truncate
) {
103 // cerr<<"Wants TRUNCATE for "<<dr.d_name<<": ";
104 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: Truncate
;
106 else if ( crcTarget
== noaction
) {
107 // cerr<<"Wants NOACTION for "<<dr.d_name<<": ";
108 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: NoAction
;
110 /* "The special RPZ encodings which are not to be taken as Local Data are
111 CNAMEs with targets that are:
112 + "." (NXDOMAIN action),
113 + "*." (NODATA action),
114 + a top level domain starting with "rpz-",
115 + a child of a top level domain starting with "rpz-".
117 else if (! crcTarget
. empty () && ! crcTarget
. isRoot () && crcTarget
. getRawLabel ( crcTarget
. countLabels () - 1 ). compare ( 0 , rpzPrefix
. length (), rpzPrefix
) == 0 ) {
118 /* this is very likely an higher format number or a configuration error,
119 let's just ignore it. */
120 g_log
<< Logger :: Info
<< "Discarding unsupported RPZ entry " << crcTarget
<< " for " << dr
. d_name
<< endl
;
124 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: Custom
;
125 pol
. d_custom
. emplace_back ( dr
. d_content
);
126 // cerr<<"Wants custom "<<crcTarget<<" for "<<dr.d_name<<": ";
130 if ( defpol
&& defpolOverrideLocal
) {
132 defpolApplied
= true ;
135 pol
. d_kind
= DNSFilterEngine :: PolicyKind :: Custom
;
136 pol
. d_custom
. emplace_back ( dr
. d_content
);
137 // cerr<<"Wants custom "<<dr.d_content->getZoneRepresentation()<<" for "<<dr.d_name<<": ";
141 if (! defpolApplied
|| defpol
-> d_ttl
< 0 ) {
142 pol
. d_ttl
= static_cast < int32_t >( std :: min ( maxTTL
, dr
. d_ttl
));
144 pol
. d_ttl
= static_cast < int32_t >( std :: min ( maxTTL
, static_cast < uint32_t >( pol
. d_ttl
)));
147 // now to DO something with that
149 if ( dr
. d_name
. isPartOf ( rpzNSDname
)) {
150 DNSName filt
= dr
. d_name
. makeRelative ( rpzNSDname
);
152 zone
-> addNSTrigger ( filt
, std :: move ( pol
), defpolApplied
);
154 zone
-> rmNSTrigger ( filt
, std :: move ( pol
));
155 } else if ( dr
. d_name
. isPartOf ( rpzClientIP
)) {
156 DNSName filt
= dr
. d_name
. makeRelative ( rpzClientIP
);
157 auto nm
= makeNetmaskFromRPZ ( filt
);
159 zone
-> addClientTrigger ( nm
, std :: move ( pol
), defpolApplied
);
161 zone
-> rmClientTrigger ( nm
, std :: move ( pol
));
163 } else if ( dr
. d_name
. isPartOf ( rpzIP
)) {
164 // cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
165 DNSName filt
= dr
. d_name
. makeRelative ( rpzIP
);
166 auto nm
= makeNetmaskFromRPZ ( filt
);
168 zone
-> addResponseTrigger ( nm
, std :: move ( pol
), defpolApplied
);
170 zone
-> rmResponseTrigger ( nm
, std :: move ( pol
));
171 } else if ( dr
. d_name
. isPartOf ( rpzNSIP
)) {
172 DNSName filt
= dr
. d_name
. makeRelative ( rpzNSIP
);
173 auto nm
= makeNetmaskFromRPZ ( filt
);
175 zone
-> addNSIPTrigger ( nm
, std :: move ( pol
), defpolApplied
);
177 zone
-> rmNSIPTrigger ( nm
, std :: move ( pol
));
180 /* if we did override the existing policy with the default policy,
181 we might turn two A or AAAA into a CNAME, which would trigger
182 an exception. Let's just ignore it. */
183 zone
-> addQNameTrigger ( dr
. d_name
, std :: move ( pol
), defpolApplied
);
186 zone
-> rmQNameTrigger ( dr
. d_name
, std :: move ( pol
));
191 static shared_ptr
< SOARecordContent
> loadRPZFromServer ( const shared_ptr
< Logr :: Logger
>& plogger
, const ComboAddress
& primary
, const DNSName
& zoneName
, std :: shared_ptr
< DNSFilterEngine :: Zone
> zone
, const boost :: optional
< DNSFilterEngine :: Policy
>& defpol
, bool defpolOverrideLocal
, uint32_t maxTTL
, const TSIGTriplet
& tt
, size_t maxReceivedBytes
, const ComboAddress
& localAddress
, uint16_t axfrTimeout
)
194 auto logger
= plogger
-> withValues ( "primary" , Logging :: Loggable ( primary
));
195 SLOG ( g_log
<< Logger :: Warning
<< "Loading RPZ zone '" << zoneName
<< "' from " << primary
. toStringWithPort ()<< endl
,
196 logger
-> info ( Logr :: Info
, "Loading RPZ from nameserver" ));
197 logger
= logger
-> v ( 1 );
198 if (! tt
. name
. empty ()) {
199 SLOG ( g_log
<< Logger :: Warning
<< "With TSIG key '" << tt
. name
<< "' of algorithm '" << tt
. algo
<< "'" << endl
,
200 logger
-> info ( Logr :: Info
, "Using TSIG key for authentication" , "tsig_key_name" , Logging :: Loggable ( tt
. name
), "tsig_key_algorithm" , Logging :: Loggable ( tt
. algo
)));
203 ComboAddress
local ( localAddress
);
204 if ( local
== ComboAddress ())
205 local
= pdns :: getQueryLocalAddress ( primary
. sin4
. sin_family
, 0 );
207 AXFRRetriever
axfr ( primary
, zoneName
, tt
, & local
, maxReceivedBytes
, axfrTimeout
);
208 unsigned int nrecords
= 0 ;
210 vector
< DNSRecord
> chunk
;
212 time_t axfrStart
= time ( nullptr );
213 time_t axfrNow
= time ( nullptr );
214 shared_ptr
< SOARecordContent
> sr
;
215 while ( axfr
. getChunk ( nop
, & chunk
, ( axfrStart
+ axfrTimeout
- axfrNow
))) {
216 for ( auto & dr
: chunk
) {
217 if ( dr
. d_type
== QType :: NS
|| dr
. d_type
== QType :: TSIG
) {
221 dr
. d_name
. makeUsRelative ( zoneName
);
222 if ( dr
. d_type
== QType :: SOA
) {
223 sr
= getRR
< SOARecordContent
>( dr
);
227 RPZRecordToPolicy ( dr
, zone
, true , defpol
, defpolOverrideLocal
, maxTTL
);
230 axfrNow
= time ( nullptr );
231 if ( axfrNow
< axfrStart
|| axfrNow
- axfrStart
> axfrTimeout
) {
232 throw PDNSException ( "Total AXFR time exceeded!" );
234 if ( last
!= time ( 0 )) {
235 SLOG ( g_log
<< Logger :: Info
<< "Loaded & indexed " << nrecords
<< " policy records so far for RPZ zone '" << zoneName
<< "'" << endl
,
236 logger
-> info ( Logr :: Info
, "RPZ load in progress" , "nrecords" , Logging :: Loggable ( nrecords
)));
240 SLOG ( g_log
<< Logger :: Info
<< "Done: " << nrecords
<< " policy records active, SOA: " << sr
-> getZoneRepresentation ()<< endl
,
241 logger
-> info ( Logr :: Info
, "RPZ load completed" , "nrecords" , Logging :: Loggable ( nrecords
), "soa" , Logging :: Loggable ( sr
-> getZoneRepresentation ())));
245 static LockGuarded
< std :: unordered_map
< std :: string
, shared_ptr
< rpzStats
> > > s_rpzStats
;
247 shared_ptr
< rpzStats
> getRPZZoneStats ( const std :: string
& zone
)
249 auto stats
= s_rpzStats
. lock ();
250 auto it
= stats
-> find ( zone
);
251 if ( it
== stats
-> end ()) {
252 auto stat
= std :: make_shared
< rpzStats
>();
253 (* stats
)[ zone
] = stat
;
259 static void incRPZFailedTransfers ( const std :: string
& zone
)
261 auto stats
= getRPZZoneStats ( zone
);
262 if ( stats
!= nullptr )
263 stats
-> d_failedTransfers
++;
266 static void setRPZZoneNewState ( const std :: string
& zone
, uint32_t serial
, uint64_t numberOfRecords
, bool fromFile
, bool wasAXFR
)
268 auto stats
= getRPZZoneStats ( zone
);
269 if ( stats
== nullptr ) {
273 stats
-> d_successfulTransfers
++;
275 stats
-> d_fullTransfers
++;
278 stats
-> d_lastUpdate
= time ( nullptr );
279 stats
-> d_serial
= serial
;
280 stats
-> d_numberOfRecords
= numberOfRecords
;
283 // this function is silent - you do the logging
284 std :: shared_ptr
< SOARecordContent
> loadRPZFromFile ( const std :: string
& fname
, std :: shared_ptr
< DNSFilterEngine :: Zone
> zone
, const boost :: optional
< DNSFilterEngine :: Policy
>& defpol
, bool defpolOverrideLocal
, uint32_t maxTTL
)
286 shared_ptr
< SOARecordContent
> sr
= nullptr ;
287 ZoneParserTNG
zpt ( fname
);
288 zpt
. setMaxGenerateSteps (:: arg (). asNum ( "max-generate-steps" ));
289 zpt
. setMaxIncludes (:: arg (). asNum ( "max-include-depth" ));
290 DNSResourceRecord drr
;
292 while ( zpt
. get ( drr
)) {
294 if ( drr
. qtype
. getCode () == QType :: CNAME
&& drr
. content
. empty ())
297 if ( dr
. d_type
== QType :: SOA
) {
298 sr
= getRR
< SOARecordContent
>( dr
);
300 zone
-> setDomain ( domain
);
302 else if ( dr
. d_type
== QType :: NS
) {
306 dr
. d_name
= dr
. d_name
. makeRelative ( domain
);
307 RPZRecordToPolicy ( dr
, zone
, true , defpol
, defpolOverrideLocal
, maxTTL
);
310 catch ( const PDNSException
& pe
) {
311 throw PDNSException ( "Issue parsing '" + drr
. qname
. toLogString ()+ "' '" + drr
. content
+ "' at " + zpt
. getLineOfFile ()+ ": " + pe
. reason
);
316 zone
-> setRefresh ( sr
-> d_st
. refresh
);
317 setRPZZoneNewState ( zone
-> getName (), sr
-> d_st
. serial
, zone
-> size (), true , false );
322 static bool dumpZoneToDisk ( const shared_ptr
< Logr :: Logger
>& plogger
, const DNSName
& zoneName
, const std :: shared_ptr
< DNSFilterEngine :: Zone
>& newZone
, const std :: string
& dumpZoneFileName
)
324 auto logger
= plogger
-> v ( 1 );
325 logger
-> info ( "Dumping zone to disk" , "destination_file" , Logging :: Loggable ( dumpZoneFileName
));
326 std :: string temp
= dumpZoneFileName
+ "XXXXXX" ;
327 int fd
= mkstemp (& temp
. at ( 0 ));
329 SLOG ( g_log
<< Logger :: Warning
<< "Unable to open a file to dump the content of the RPZ zone " << zoneName
<< endl
,
330 logger
-> error ( Logr :: Warning
, errno
, "Unable to create temporary file" ));
334 auto fp
= std :: unique_ptr
< FILE , int (*)( FILE *)>( fdopen ( fd
, "w+" ), fclose
);
338 SLOG ( g_log
<< Logger :: Warning
<< "Unable to open a file pointer to dump the content of the RPZ zone " << zoneName
<< endl
,
339 logger
-> error ( Logr :: Warning
, err
, "Unable to open file pointer" ));
345 newZone
-> dump ( fp
. get ());
347 catch ( const std :: exception
& e
) {
348 SLOG ( g_log
<< Logger :: Warning
<< "Error while dumping the content of the RPZ zone " << zoneName
<< ": " << e
. what ()<< endl
,
349 logger
-> error ( Logr :: Warning
, e
. what (), "Error while dumping the content of the RPZ" ));
353 if ( fflush ( fp
. get ()) != 0 ) {
354 SLOG ( g_log
<< Logger :: Warning
<< "Error while flushing the content of the RPZ zone " << zoneName
<< " to the dump file: " << stringerror ()<< endl
,
355 logger
-> error ( Logr :: Warning
, errno
, "Error while flushing the content of the RPZ" ));
359 if ( fsync ( fileno ( fp
. get ())) != 0 ) {
360 SLOG ( g_log
<< Logger :: Warning
<< "Error while syncing the content of the RPZ zone " << zoneName
<< " to the dump file: " << stringerror ()<< endl
,
361 logger
-> error ( Logr :: Warning
, errno
, "Error while syncing the content of the RPZ" ));
365 if ( fclose ( fp
. release ()) != 0 ) {
366 SLOG ( g_log
<< Logger :: Warning
<< "Error while writing the content of the RPZ zone " << zoneName
<< " to the dump file: " << stringerror ()<< endl
,
367 logger
-> error ( Logr :: Warning
, errno
, "Error while writing the content of the RPZ" ));
371 if ( rename ( temp
. c_str (), dumpZoneFileName
. c_str ()) != 0 ) {
372 SLOG ( g_log
<< Logger :: Warning
<< "Error while moving the content of the RPZ zone " << zoneName
<< " to the dump file: " << stringerror ()<< endl
,
373 logger
-> error ( Logr :: Warning
, errno
, "Error while moving the content of the RPZ" , "destination_file" , Logging :: Loggable ( dumpZoneFileName
)));
380 void RPZIXFRTracker ( const std :: vector
< ComboAddress
>& primaries
, const 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
, const uint32_t refreshFromConf
, std :: shared_ptr
< SOARecordContent
> sr
, const std :: string
& dumpZoneFileName
, uint64_t configGeneration
)
382 setThreadName ( "pdns-r/RPZIXFR" );
383 bool isPreloaded
= sr
!= nullptr ;
384 auto luaconfsLocal
= g_luaconfs
. getLocal ();
386 auto logger
= g_slog
-> withName ( "rpz" )-> v ( 1 );
388 /* we can _never_ modify this zone directly, we need to do a full copy then replace the existing zone */
389 std :: shared_ptr
< DNSFilterEngine :: Zone
> oldZone
= luaconfsLocal
-> dfe
. getZone ( zoneIdx
);
391 SLOG ( g_log
<< Logger :: Error
<< "Unable to retrieve RPZ zone with index " << zoneIdx
<< " from the configuration, exiting" << endl
,
392 logger
-> error ( Logr :: Error
, "Unable to retrieve RPZ zone from configuration" , "index" , Logging :: Loggable ( zoneIdx
)));
396 // If oldZone failed to load its getRefresh() returns 0, protect against that
397 uint32_t refresh
= std :: max ( refreshFromConf
? refreshFromConf
: oldZone
-> getRefresh (), 10U );
398 DNSName zoneName
= oldZone
-> getDomain ();
399 std :: string polName
= ! oldZone
-> getName (). empty () ? oldZone
-> getName () : zoneName
. toStringNoDot ();
401 // Now that we know the name, set it in the logger
402 logger
= logger
-> withValues ( "zone" , Logging :: Loggable ( zoneName
));
405 /* if we received an empty sr, the zone was not really preloaded */
407 /* full copy, as promised */
408 std :: shared_ptr
< DNSFilterEngine :: Zone
> newZone
= std :: make_shared
< DNSFilterEngine :: Zone
>(* oldZone
);
409 for ( const auto & primary
: primaries
) {
411 sr
= loadRPZFromServer ( logger
, primary
, zoneName
, newZone
, defpol
, defpolOverrideLocal
, maxTTL
, tt
, maxReceivedBytes
, localAddress
, axfrTimeout
);
412 newZone
-> setSerial ( sr
-> d_st
. serial
);
413 newZone
-> setRefresh ( sr
-> d_st
. refresh
);
414 refresh
= std :: max ( refreshFromConf
? refreshFromConf
: newZone
-> getRefresh (), 1U );
415 setRPZZoneNewState ( polName
, sr
-> d_st
. serial
, newZone
-> size (), false , true );
417 g_luaconfs
. modify ([ zoneIdx
, & newZone
]( LuaConfigItems
& lci
) {
418 lci
. dfe
. setZone ( zoneIdx
, newZone
);
421 if (! dumpZoneFileName
. empty ()) {
422 dumpZoneToDisk ( logger
, zoneName
, newZone
, dumpZoneFileName
);
425 /* no need to try another primary */
428 catch ( const std :: exception
& e
) {
429 SLOG ( g_log
<< Logger :: Warning
<< "Unable to load RPZ zone '" << zoneName
<< "' from '" << primary
<< "': '" << e
. what ()<< "'. (Will try again in " << refresh
<< " seconds...)" << endl
,
430 logger
-> info ( Logr :: Warning
, "Unable to load RPZ zone, will retry" , "from" , Logging :: Loggable ( primary
), "exception" , Logging :: Loggable ( e
. what ()), "refresh" , Logging :: Loggable ( refresh
)));
431 incRPZFailedTransfers ( polName
);
433 catch ( const PDNSException
& e
) {
434 SLOG ( g_log
<< Logger :: Warning
<< "Unable to load RPZ zone '" << zoneName
<< "' from '" << primary
<< "': '" << e
. reason
<< "'. (Will try again in " << refresh
<< " seconds...)" << endl
,
435 logger
-> info ( Logr :: Warning
, "Unable to load RPZ zone, will retry" , "from" , Logging :: Loggable ( primary
), "exception" , Logging :: Loggable ( e
. reason
), "refresh" , Logging :: Loggable ( refresh
)));
436 incRPZFailedTransfers ( polName
);
445 bool skipRefreshDelay
= isPreloaded
;
451 if ( skipRefreshDelay
) {
452 skipRefreshDelay
= false ;
458 if ( luaconfsLocal
-> generation
!= configGeneration
) {
459 /* the configuration has been reloaded, meaning that a new thread
460 has been started to handle that zone and we are now obsolete.
462 g_log
<< Logger :: Info
<< "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName
<< endl
;
466 vector
< pair
< vector
< DNSRecord
>, vector
< DNSRecord
> > > deltas
;
467 for ( const auto & primary
: primaries
) {
468 g_log
<< Logger :: Info
<< "Getting IXFR deltas for " << zoneName
<< " from " << primary
. toStringWithPort ()<< ", our serial: " << getRR
< SOARecordContent
>( dr
)-> d_st
. serial
<< endl
;
470 ComboAddress
local ( localAddress
);
471 if ( local
== ComboAddress ()) {
472 local
= pdns :: getQueryLocalAddress ( primary
. sin4
. sin_family
, 0 );
476 deltas
= getIXFRDeltas ( primary
, zoneName
, dr
, tt
, & local
, maxReceivedBytes
);
478 /* no need to try another primary */
480 } catch ( const std :: runtime_error
& e
){
481 g_log
<< Logger :: Warning
<< e
. what ()<< endl
;
482 incRPZFailedTransfers ( polName
);
492 g_log
<< Logger :: Info
<< "Processing " << deltas
. size ()<< " delta" << addS ( deltas
)<< " for RPZ " << zoneName
<< endl
;
494 if ( luaconfsLocal
-> generation
!= configGeneration
) {
495 g_log
<< Logger :: Info
<< "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName
<< endl
;
498 oldZone
= luaconfsLocal
-> dfe
. getZone ( zoneIdx
);
499 if (! oldZone
|| oldZone
-> getDomain () != zoneName
) {
500 g_log
<< Logger :: Info
<< "This policy is no more, stopping the existing RPZ update thread for " << zoneName
<< endl
;
503 /* we need to make a _full copy_ of the zone we are going to work on */
504 std :: shared_ptr
< DNSFilterEngine :: Zone
> newZone
= std :: make_shared
< DNSFilterEngine :: Zone
>(* oldZone
);
505 /* initialize the current serial to the last one */
506 std :: shared_ptr
< SOARecordContent
> currentSR
= sr
;
508 int totremove
= 0 , totadd
= 0 ;
509 bool fullUpdate
= false ;
510 for ( const auto & delta
: deltas
) {
511 const auto & remove
= delta
. first
;
512 const auto & add
= delta
. second
;
514 g_log
<< Logger :: Warning
<< "IXFR update is a whole new zone" << endl
;
518 for ( const auto & rr
: remove
) { // should always contain the SOA
519 if ( rr
. d_type
== QType :: NS
)
521 if ( rr
. d_type
== QType :: SOA
) {
522 auto oldsr
= getRR
< SOARecordContent
>( rr
);
523 if ( oldsr
&& oldsr
-> d_st
. serial
== currentSR
-> d_st
. serial
) {
524 // cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
528 throw std :: runtime_error ( "Unable to extract serial from SOA record while processing the removal part of an update" );
531 throw std :: runtime_error ( "Received an unexpected serial (" + std :: to_string ( oldsr
-> d_st
. serial
) + ", expecting " + std :: to_string ( currentSR
-> d_st
. serial
) + ") from SOA record while processing the removal part of an update" );
537 g_log
<<( g_logRPZChanges
? Logger :: Info
: Logger :: Debug
)<< "Had removal of " << rr
. d_name
<< " from RPZ zone " << zoneName
<< endl
;
538 RPZRecordToPolicy ( rr
, newZone
, false , defpol
, defpolOverrideLocal
, maxTTL
);
542 for ( const auto & rr
: add
) { // should always contain the new SOA
543 if ( rr
. d_type
== QType :: NS
)
545 if ( rr
. d_type
== QType :: SOA
) {
546 auto tempSR
= getRR
< SOARecordContent
>( rr
);
547 // g_log<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<currentSR->d_st.serial<<endl;
554 g_log
<<( g_logRPZChanges
? Logger :: Info
: Logger :: Debug
)<< "Had addition of " << rr
. d_name
<< " to RPZ zone " << zoneName
<< endl
;
555 RPZRecordToPolicy ( rr
, newZone
, true , defpol
, defpolOverrideLocal
, maxTTL
);
560 /* only update sr now that all changes have been converted */
564 g_log
<< Logger :: Info
<< "Had " << totremove
<< " RPZ removal" << addS ( totremove
)<< ", " << totadd
<< " addition" << addS ( totadd
)<< " for " << zoneName
<< " New serial: " << sr
-> d_st
. serial
<< endl
;
565 newZone
-> setSerial ( sr
-> d_st
. serial
);
566 newZone
-> setRefresh ( sr
-> d_st
. refresh
);
567 setRPZZoneNewState ( polName
, sr
-> d_st
. serial
, newZone
-> size (), false , fullUpdate
);
569 /* we need to replace the existing zone with the new one,
570 but we don't want to touch anything else, especially other zones,
571 since they might have been updated by another RPZ IXFR tracker thread.
573 if ( luaconfsLocal
-> generation
!= configGeneration
) {
574 g_log
<< Logger :: Info
<< "A more recent configuration has been found, stopping the existing RPZ update thread for " << zoneName
<< endl
;
577 g_luaconfs
. modify ([ zoneIdx
, & newZone
]( LuaConfigItems
& lci
) {
578 lci
. dfe
. setZone ( zoneIdx
, newZone
);
581 if (! dumpZoneFileName
. empty ()) {
582 dumpZoneToDisk ( logger
, zoneName
, newZone
, dumpZoneFileName
);
584 refresh
= std :: max ( refreshFromConf
? refreshFromConf
: newZone
-> getRefresh (), 1U );
586 catch ( const std :: exception
& e
) {
587 g_log
<< Logger :: Error
<< "Error while applying the update received over XFR for " << zoneName
<< ", skipping the update: " << e
. what () << endl
;