]>
git.ipfire.org Git - thirdparty/pdns.git/blob - modules/lmdbbackend/lmdbbackend.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "pdns/utility.hh"
26 #include "pdns/dnsbackend.hh"
27 #include "pdns/dns.hh"
28 #include "pdns/dnspacket.hh"
29 #include "pdns/base32.hh"
30 #include "pdns/dnssecinfra.hh"
31 #include "pdns/pdnsexception.hh"
32 #include "pdns/logger.hh"
33 #include "pdns/version.hh"
34 #include "pdns/arguments.hh"
35 #include <boost/archive/binary_oarchive.hpp>
36 #include <boost/archive/binary_iarchive.hpp>
37 #include <boost/serialization/vector.hpp>
38 #include <boost/serialization/string.hpp>
39 #include <boost/serialization/utility.hpp>
40 // #include <boost/iostreams/stream.hpp>
41 // #include <boost/iostreams/stream_buffer.hpp>
43 #include <boost/iostreams/device/back_inserter.hpp>
47 #include "lmdbbackend.hh"
49 #define SCHEMAVERSION 1
51 LMDBBackend :: LMDBBackend ( const std :: string
& suffix
)
53 setArgPrefix ( "lmdb" + suffix
);
55 string syncMode
= toLower ( getArg ( "sync-mode" ));
57 if ( syncMode
== "nosync" )
58 d_asyncFlag
= MDB_NOSYNC
;
59 else if ( syncMode
== "nometasync" )
60 d_asyncFlag
= MDB_NOMETASYNC
;
61 else if ( syncMode
== "mapasync" )
62 d_asyncFlag
= MDB_MAPASYNC
;
63 else if ( syncMode
. empty () || syncMode
== "sync" )
66 throw std :: runtime_error ( "Unknown sync mode " + syncMode
+ " requested for LMDB backend" );
68 d_tdomains
= std :: make_shared
< tdomains_t
>( getMDBEnv ( getArg ( "filename" ). c_str (), MDB_NOSUBDIR
| d_asyncFlag
, 0600 ), "domains" );
69 d_tmeta
= std :: make_shared
< tmeta_t
>( d_tdomains
-> getEnv (), "metadata" );
70 d_tkdb
= std :: make_shared
< tkdb_t
>( d_tdomains
-> getEnv (), "keydata" );
71 d_ttsig
= std :: make_shared
< ttsig_t
>( d_tdomains
-> getEnv (), "tsig" );
73 auto pdnsdbi
= d_tdomains
-> getEnv ()-> openDB ( "pdns" , MDB_CREATE
);
74 auto txn
= d_tdomains
-> getEnv ()-> getRWTransaction ();
75 MDBOutVal _schemaversion
;
76 if (! txn
-> get ( pdnsdbi
, "schemaversion" , _schemaversion
)) {
77 auto schemaversion
= _schemaversion
. get
< uint32_t >();
78 if ( schemaversion
!= SCHEMAVERSION
) {
79 throw std :: runtime_error ( "Expected LMDB schema version " + std :: to_string ( SCHEMAVERSION
)+ " but got " + std :: to_string ( schemaversion
));
83 txn
-> put ( pdnsdbi
, "schemaversion" , SCHEMAVERSION
);
86 if (! txn
-> get ( pdnsdbi
, "shards" , shards
)) {
88 d_shards
= shards
. get
< uint32_t >();
89 if ( d_shards
!= atoi ( getArg ( "shards" ). c_str ())) {
90 g_log
<< Logger :: Warning
<< "Note: configured number of lmdb shards (" << atoi ( getArg ( "shards" ). c_str ())<< ") is different from on-disk (" << d_shards
<< "). Using on-disk shard number" << endl
;
94 d_shards
= atoi ( getArg ( "shards" ). c_str ());
95 txn
-> put ( pdnsdbi
, "shards" , d_shards
);
98 d_trecords
. resize ( d_shards
);
99 d_dolog
= :: arg (). mustDo ( "query-logging" );
105 namespace serialization
{
107 template < class Archive
>
108 void save ( Archive
& ar
, const DNSName
& g
, const unsigned int version
)
111 std :: string tmp
= g
. toDNSStringLC (); // g++ 4.8 woes
118 template < class Archive
>
119 void load ( Archive
& ar
, DNSName
& g
, const unsigned int version
)
126 g
= DNSName ( tmp
. c_str (), tmp
. size (), 0 , false );
129 template < class Archive
>
130 void save ( Archive
& ar
, const QType
& g
, const unsigned int version
)
132 uint16_t tmp
= g
. getCode (); // g++ 4.8 woes
136 template < class Archive
>
137 void load ( Archive
& ar
, QType
& g
, const unsigned int version
)
144 template < class Archive
>
145 void serialize ( Archive
& ar
, DomainInfo
& g
, const unsigned int version
)
152 ar
& g
. notified_serial
;
156 template < class Archive
>
157 void serialize ( Archive
& ar
, LMDBBackend :: DomainMeta
& g
, const unsigned int version
)
159 ar
& g
. domain
& g
. key
& g
. value
;
162 template < class Archive
>
163 void serialize ( Archive
& ar
, LMDBBackend :: KeyDataDB
& g
, const unsigned int version
)
165 ar
& g
. domain
& g
. content
& g
. flags
& g
. active
;
168 template < class Archive
>
169 void serialize ( Archive
& ar
, TSIGKey
& g
, const unsigned int version
)
172 ar
& g
. algorithm
; // this is the ordername
178 } // namespace serialization
181 BOOST_SERIALIZATION_SPLIT_FREE ( DNSName
);
182 BOOST_SERIALIZATION_SPLIT_FREE ( QType
);
183 BOOST_IS_BITWISE_SERIALIZABLE ( ComboAddress
);
186 std :: string
serToString ( const DNSResourceRecord
& rr
)
188 // only does content, ttl, auth
190 uint16_t len
= rr
. content
. length ();
191 ret
. reserve ( 2 + len
+ 8 );
193 ret
. assign (( const char *)& len
, 2 );
195 ret
. append (( const char *)& rr
. ttl
, 4 );
196 ret
. append ( 1 , ( char ) rr
. auth
);
197 ret
. append ( 1 , ( char ) false );
198 ret
. append ( 1 , ( char ) rr
. disabled
);
203 void serFromString ( const string_view
& str
, DNSResourceRecord
& rr
)
206 memcpy (& len
, & str
[ 0 ], 2 );
207 rr
. content
. assign (& str
[ 2 ], len
); // len bytes
208 memcpy (& rr
. ttl
, & str
[ 2 ] + len
, 4 );
209 rr
. auth
= str
[ str
. size ()- 3 ];
210 rr
. disabled
= str
[ str
. size ()- 1 ];
211 rr
. wildcardname
. clear ();
215 std :: string
serializeContent ( uint16_t qtype
, const DNSName
& domain
, const std :: string
& content
)
217 auto drc
= DNSRecordContent :: mastermake ( qtype
, 1 , content
);
218 return drc
-> serialize ( domain
, false );
221 std :: shared_ptr
< DNSRecordContent
> unserializeContentZR ( uint16_t qtype
, const DNSName
& qname
, const std :: string
& content
)
223 if ( qtype
== QType :: A
&& content
. size () == 4 ) {
224 return std :: make_shared
< ARecordContent
>(*(( uint32_t *) content
. c_str ()));
226 return DNSRecordContent :: unserialize ( qname
, qtype
, content
);
230 /* design. If you ask a question without a zone id, we lookup the best
231 zone id for you, and answer from that. This is different than other backends, but I can't see why it would not work.
233 The index we use is "zoneid,canonical relative name". This index is also used
236 Note - domain_id, name and type are ONLY present on the index!
239 #if BOOST_VERSION >= 106100
240 #define StringView string_view
242 #define StringView string
245 void LMDBBackend :: deleteDomainRecords ( RecordsRWTransaction
& txn
, uint32_t domain_id
, uint16_t qtype
)
247 compoundOrdername co
;
248 string match
= co ( domain_id
);
250 auto cursor
= txn
. txn
-> getCursor ( txn
. db
-> dbi
);
252 // cout<<"Match: "<<makeHexDump(match);
253 if (! cursor
. lower_bound ( match
, key
, val
) ) {
254 while ( key
. get
< StringView
>(). rfind ( match
, 0 ) == 0 ) {
255 if ( qtype
== QType :: ANY
|| co
. getQType ( key
. get
< StringView
>()) == qtype
)
256 cursor
. del ( MDB_NODUPDATA
);
257 if ( cursor
. next ( key
, val
)) break ;
262 /* Here's the complicated story. Other backends have just one transaction, which is either
265 You can't call feedRecord without a transaction started with startTransaction.
267 However, other functions can be called after startTransaction() or without startTransaction()
268 (like updateDNSSECOrderNameAndAuth)
274 bool LMDBBackend :: startTransaction ( const DNSName
& domain
, int domain_id
)
276 // cout <<"startTransaction("<<domain<<", "<<domain_id<<")"<<endl;
277 int real_id
= domain_id
;
279 auto rotxn
= d_tdomains
-> getROTransaction ();
281 real_id
= rotxn
. get
< 0 >( domain
, di
);
282 // cout<<"real_id = "<<real_id << endl;
287 throw DBException ( "Attempt to start a transaction while one was open already" );
289 d_rwtxn
= getRecordsRWTransaction ( real_id
);
291 d_transactiondomain
= domain
;
292 d_transactiondomainid
= real_id
;
294 deleteDomainRecords (* d_rwtxn
, domain_id
);
300 bool LMDBBackend :: commitTransaction ()
302 // cout<<"Commit transaction" <<endl;
303 d_rwtxn
-> txn
-> commit ();
308 bool LMDBBackend :: abortTransaction ()
310 // cout<<"Abort transaction"<<endl;
311 d_rwtxn
-> txn
-> abort ();
317 // d_rwtxn must be set here
318 bool LMDBBackend :: feedRecord ( const DNSResourceRecord
& r
, const DNSName
& ordername
, bool ordernameIsNSEC3
)
320 DNSResourceRecord
rr ( r
);
321 rr
. qname
. makeUsRelative ( d_transactiondomain
);
322 rr
. content
= serializeContent ( rr
. qtype
. getCode (), r
. qname
, rr
. content
);
325 compoundOrdername co
;
326 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( r
. domain_id
, rr
. qname
, rr
. qtype
. getCode ()), serToString ( rr
));
328 if ( ordernameIsNSEC3
&& ! ordername
. empty ()) {
330 if ( d_rwtxn
-> txn
-> get ( d_rwtxn
-> db
-> dbi
, co ( r
. domain_id
, rr
. qname
, QType :: NSEC3
), val
)) {
332 rr
. content
= rr
. qname
. toDNSStringLC ();
334 string ser
= serToString ( rr
);
335 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( r
. domain_id
, ordername
, QType :: NSEC3
), ser
);
338 rr
. content
= ordername
. toDNSString ();
339 ser
= serToString ( rr
);
340 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( r
. domain_id
, rr
. qname
, QType :: NSEC3
), ser
);
346 bool LMDBBackend :: feedEnts ( int domain_id
, map
< DNSName
, bool >& nonterm
)
348 DNSResourceRecord rr
;
350 compoundOrdername co
;
351 for ( const auto & nt
: nonterm
) {
352 rr
. qname
= nt
. first
. makeRelative ( d_transactiondomain
);
356 std :: string ser
= serToString ( rr
);
357 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( domain_id
, rr
. qname
, 0 ), ser
);
362 bool LMDBBackend :: feedEnts3 ( int domain_id
, const DNSName
& domain
, map
< DNSName
, bool > & nonterm
, const NSEC3PARAMRecordContent
& ns3prc
, bool narrow
)
366 DNSResourceRecord rr
;
367 compoundOrdername co
;
368 for ( const auto & nt
: nonterm
) {
369 rr
. qname
= nt
. first
. makeRelative ( domain
);
372 rr
. disabled
= nt
. second
;
373 ser
= serToString ( rr
);
374 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( domain_id
, rr
. qname
, 0 ), ser
);
376 if (! narrow
&& rr
. auth
) {
377 rr
. content
= rr
. qname
. toDNSString ();
380 ser
= serToString ( rr
);
382 ordername
= DNSName ( toBase32Hex ( hashQNameWithSalt ( ns3prc
, nt
. first
)));
383 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( domain_id
, ordername
, QType :: NSEC3
), ser
);
386 rr
. content
= ordername
. toDNSString ();
387 ser
= serToString ( rr
);
388 d_rwtxn
-> txn
-> put ( d_rwtxn
-> db
-> dbi
, co ( domain_id
, rr
. qname
, QType :: NSEC3
), ser
);
395 // might be called within a transaction, might also be called alone
396 bool LMDBBackend :: replaceRRSet ( uint32_t domain_id
, const DNSName
& qname
, const QType
& qt
, const vector
< DNSResourceRecord
>& rrset
)
398 // zonk qname/qtype within domain_id (go through qname, check domain_id && qtype)
399 shared_ptr
< RecordsRWTransaction
> txn
;
400 bool needCommit
= false ;
401 if ( d_rwtxn
&& d_transactiondomainid
== domain_id
) {
403 // cout<<"Reusing open transaction"<<endl;
406 // cout<<"Making a new RW txn for replace rrset"<<endl;
407 txn
= getRecordsRWTransaction ( domain_id
);
412 if (! d_tdomains
-> getROTransaction (). get ( domain_id
, di
)) {
416 compoundOrdername co
;
417 auto cursor
= txn
-> txn
-> getCursor ( txn
-> db
-> dbi
);
419 string match
= co ( domain_id
, qname
. makeRelative ( di
. zone
), qt
. getCode ());
420 if (! cursor
. find ( match
, key
, val
)) {
422 cursor
. del ( MDB_NODUPDATA
);
423 } while (! cursor
. next ( key
, val
) && key
. get
< StringView
>(). rfind ( match
, 0 ) == 0 );
426 for ( auto rr
: rrset
) {
427 rr
. content
= serializeContent ( rr
. qtype
. getCode (), rr
. qname
, rr
. content
);
428 rr
. qname
. makeUsRelative ( di
. zone
);
429 txn
-> txn
-> put ( txn
-> db
-> dbi
, match
, serToString ( rr
));
438 // tempting to templatize these two functions but the pain is not worth it
439 std :: shared_ptr
< LMDBBackend :: RecordsRWTransaction
> LMDBBackend :: getRecordsRWTransaction ( uint32_t id
)
441 auto & shard
= d_trecords
[ id
% d_shards
];
443 shard
. env
= getMDBEnv ( ( getArg ( "filename" )+ "-" + std :: to_string ( id
% d_shards
)). c_str (),
444 MDB_NOSUBDIR
| d_asyncFlag
, 0600 );
445 shard
. dbi
= shard
. env
-> openDB ( "records" , MDB_CREATE
| MDB_DUPSORT
);
447 auto ret
= std :: make_shared
< RecordsRWTransaction
>( shard
. env
-> getRWTransaction ());
448 ret
-> db
= std :: make_shared
< RecordsDB
>( shard
);
453 std :: shared_ptr
< LMDBBackend :: RecordsROTransaction
> LMDBBackend :: getRecordsROTransaction ( uint32_t id
, std :: shared_ptr
< LMDBBackend :: RecordsRWTransaction
> rwtxn
)
455 auto & shard
= d_trecords
[ id
% d_shards
];
458 throw DBException ( "attempting to start nested transaction without open parent env" );
460 shard
. env
= getMDBEnv ( ( getArg ( "filename" )+ "-" + std :: to_string ( id
% d_shards
)). c_str (),
461 MDB_NOSUBDIR
| d_asyncFlag
, 0600 );
462 shard
. dbi
= shard
. env
-> openDB ( "records" , MDB_CREATE
| MDB_DUPSORT
);
466 auto ret
= std :: make_shared
< RecordsROTransaction
>( rwtxn
-> txn
-> getROTransaction ());
467 ret
-> db
= std :: make_shared
< RecordsDB
>( shard
);
470 auto ret
= std :: make_shared
< RecordsROTransaction
>( shard
. env
-> getROTransaction ());
471 ret
-> db
= std :: make_shared
< RecordsDB
>( shard
);
477 bool LMDBBackend :: deleteDomain ( const DNSName
& domain
)
479 auto doms
= d_tdomains
-> getRWTransaction ();
482 auto id
= doms
. get
< 0 >( domain
, di
);
486 shared_ptr
< RecordsRWTransaction
> txn
;
487 bool needCommit
= false ;
488 if ( d_rwtxn
&& d_transactiondomainid
== id
) {
490 // cout<<"Reusing open transaction"<<endl;
493 // cout<<"Making a new RW txn for delete domain"<<endl;
494 txn
= getRecordsRWTransaction ( id
);
500 compoundOrdername co
;
503 auto cursor
= txn
-> txn
-> getCursor ( txn
-> db
-> dbi
);
505 if (! cursor
. find ( match
, key
, val
)) {
507 cursor
. del ( MDB_NODUPDATA
);
508 } while (! cursor
. next ( key
, val
) && key
. get
< StringView
>(). rfind ( match
, 0 ) == 0 );
519 bool LMDBBackend :: list ( const DNSName
& target
, int id
, bool include_disabled
)
524 auto dtxn
= d_tdomains
-> getROTransaction ();
526 if (( di
. id
= dtxn
. get
< 0 >( target
, di
)))
527 ; // cout<<"Found domain "<<target<<" on domain_id "<<di.id <<", list requested "<<id<<endl;
529 // cout<<"Did not find "<<target<<endl;
534 d_rotxn
= getRecordsROTransaction ( di
. id
);
535 compoundOrdername co
;
536 d_matchkey
= co ( di
. id
);
537 d_getcursor
= std :: make_shared
< MDBROCursor
>( d_rotxn
-> txn
-> getCursor ( d_rotxn
-> db
-> dbi
));
541 if ( d_getcursor
-> lower_bound ( d_matchkey
, key
, val
) || key
. get
< StringView
>(). rfind ( d_matchkey
, 0 ) != 0 ) {
542 // cout<<"Found nothing for list"<<endl;
547 d_lookupqname
= target
;
552 void LMDBBackend :: lookup ( const QType
& type
, const DNSName
& qdomain
, int zoneId
, DNSPacket
* p
)
555 g_log
<< Logger :: Warning
<< "Got lookup for " << qdomain
<< "|" << type
. getName ()<< " in zone " << zoneId
<< endl
;
558 DNSName
hunt ( qdomain
);
561 auto rotxn
= d_tdomains
-> getROTransaction ();
564 zoneId
= rotxn
. get
< 0 >( hunt
, di
);
565 } while (! zoneId
&& type
!= QType :: SOA
&& hunt
. chopOff ());
567 // cout << "Did not find zone for "<< qdomain<<endl;
573 if (! d_tdomains
-> getROTransaction (). get ( zoneId
, di
)) {
574 // cout<<"Could not find a zone with id "<<zoneId<<endl;
581 DNSName relqname
= qdomain
. makeRelative ( hunt
);
582 // cout<<"get will look for "<<relqname<< " in zone "<<hunt<<" with id "<<zoneId<<endl;
583 d_rotxn
= getRecordsROTransaction ( zoneId
, d_rwtxn
);
585 compoundOrdername co
;
586 d_getcursor
= std :: make_shared
< MDBROCursor
>( d_rotxn
-> txn
-> getCursor ( d_rotxn
-> db
-> dbi
));
588 if ( type
. getCode () == QType :: ANY
) {
589 d_matchkey
= co ( zoneId
, relqname
);
592 d_matchkey
= co ( zoneId
, relqname
, type
. getCode ());
596 if ( d_getcursor
-> lower_bound ( d_matchkey
, key
, val
) || key
. get
< StringView
>(). rfind ( d_matchkey
, 0 ) != 0 ) {
599 g_log
<< Logger :: Warning
<< "Query " <<(( long )( void *) this )<< ": " << d_dtime
. udiffNoReset ()<< " usec to execute (found nothing)" << endl
;
605 g_log
<< Logger :: Warning
<< "Query " <<(( long )( void *) this )<< ": " << d_dtime
. udiffNoReset ()<< " usec to execute" << endl
;
609 d_lookupqname
= qdomain
;
610 d_lookupdomain
= hunt
;
611 d_lookupdomainid
= zoneId
;
614 bool LMDBBackend :: get ( DNSZoneRecord
& rr
)
619 return get_lookup ( rr
);
622 bool LMDBBackend :: get ( DNSResourceRecord
& rr
)
624 // cout <<"Old-school get called"<<endl;
634 rr
. qname
= dzr
. dr
. d_name
;
635 rr
. ttl
= dzr
. dr
. d_ttl
;
636 rr
. qtype
= dzr
. dr
. d_type
;
637 rr
. content
= dzr
. dr
. d_content
-> getZoneRepresentation ( true );
638 rr
. domain_id
= dzr
. domain_id
;
640 // cout<<"old school called for "<<rr.qname<<", "<<rr.qtype.getName()<<endl;
644 bool LMDBBackend :: getSOA ( const DNSName
& domain
, SOAData
& sd
)
646 // cout <<"Native getSOA called"<<endl;
647 lookup ( QType ( QType :: SOA
), domain
, - 1 );
651 auto src
= getRR
< SOARecordContent
>( dzr
. dr
);
652 sd
. domain_id
= dzr
. domain_id
;
653 sd
. ttl
= dzr
. dr
. d_ttl
;
654 sd
. qname
= dzr
. dr
. d_name
;
656 sd
. nameserver
= src
-> d_mname
;
657 sd
. hostmaster
= src
-> d_rname
;
658 sd
. serial
= src
-> d_st
. serial
;
659 sd
. refresh
= src
-> d_st
. refresh
;
660 sd
. retry
= src
-> d_st
. retry
;
661 sd
. expire
= src
-> d_st
. expire
;
662 sd
. default_ttl
= src
-> d_st
. minimum
;
669 bool LMDBBackend :: get_list ( DNSZoneRecord
& rr
)
679 d_getcursor
-> current ( keyv
, val
);
680 DNSResourceRecord drr
;
681 serFromString ( val
. get
< string
>(), drr
);
683 auto key
= keyv
. get
< string_view
>();
684 rr
. dr
. d_name
= compoundOrdername :: getQName ( key
) + d_lookupqname
;
685 rr
. domain_id
= compoundOrdername :: getDomainID ( key
);
686 rr
. dr
. d_type
= compoundOrdername :: getQType ( key
). getCode ();
687 rr
. dr
. d_ttl
= drr
. ttl
;
690 if ( rr
. dr
. d_type
== QType :: NSEC3
) {
691 // cout << "Had a magic NSEC3, skipping it" << endl;
692 if ( d_getcursor
-> next ( keyv
, val
) || keyv
. get
< StringView
>(). rfind ( d_matchkey
, 0 ) != 0 ) {
697 rr
. dr
. d_content
= unserializeContentZR ( rr
. dr
. d_type
, rr
. dr
. d_name
, drr
. content
);
699 if ( d_getcursor
-> next ( keyv
, val
) || keyv
. get
< StringView
>(). rfind ( d_matchkey
, 0 ) != 0 ) {
708 bool LMDBBackend :: get_lookup ( DNSZoneRecord
& rr
)
716 d_getcursor
-> current ( keyv
, val
);
717 DNSResourceRecord drr
;
718 serFromString ( val
. get
< string
>(), drr
);
720 auto key
= keyv
. get
< string_view
>();
722 rr
. dr
. d_name
= compoundOrdername :: getQName ( key
) + d_lookupdomain
;
724 rr
. domain_id
= compoundOrdername :: getDomainID ( key
);
725 // cout << "We found "<<rr.qname<< " in zone id "<<rr.domain_id <<endl;
726 rr
. dr
. d_type
= compoundOrdername :: getQType ( key
). getCode ();
727 rr
. dr
. d_ttl
= drr
. ttl
;
728 if ( rr
. dr
. d_type
== QType :: NSEC3
) {
729 // cout << "Hit a magic NSEC3 skipping" << endl;
730 if ( d_getcursor
-> next ( keyv
, val
) || keyv
. get
< StringView
>(). rfind ( d_matchkey
, 0 ) != 0 ) {
737 rr
. dr
. d_content
= unserializeContentZR ( rr
. dr
. d_type
, rr
. dr
. d_name
, drr
. content
);
739 if ( d_getcursor
-> next ( keyv
, val
) || keyv
. get
< StringView
>(). rfind ( d_matchkey
, 0 ) != 0 ) {
751 bool LMDBBackend :: getDomainInfo ( const DNSName
& domain
, DomainInfo
& di
, bool getSerial
)
753 auto txn
= d_tdomains
-> getROTransaction ();
755 if (!( di
. id
= txn
. get
< 0 >( domain
, di
)))
762 int LMDBBackend :: genChangeDomain ( const DNSName
& domain
, std :: function
< void ( DomainInfo
&)> func
)
764 auto txn
= d_tdomains
-> getRWTransaction ();
768 auto id
= txn
. get
< 0 >( domain
, di
);
776 int LMDBBackend :: genChangeDomain ( uint32_t id
, std :: function
< void ( DomainInfo
&)> func
)
780 auto txn
= d_tdomains
-> getRWTransaction ();
782 if (! txn
. get ( id
, di
))
794 bool LMDBBackend :: setKind ( const DNSName
& domain
, const DomainInfo :: DomainKind kind
)
796 return genChangeDomain ( domain
, [ kind
]( DomainInfo
& di
) {
801 bool LMDBBackend :: setAccount ( const DNSName
& domain
, const std :: string
& account
)
803 return genChangeDomain ( domain
, [ account
]( DomainInfo
& di
) {
804 di
. account
= account
;
809 void LMDBBackend :: setFresh ( uint32_t domain_id
)
811 genChangeDomain ( domain_id
, []( DomainInfo
& di
) {
812 di
. last_check
= time ( 0 );
816 void LMDBBackend :: setNotified ( uint32_t domain_id
, uint32_t serial
)
818 genChangeDomain ( domain_id
, [ serial
]( DomainInfo
& di
) {
824 bool LMDBBackend :: setMaster ( const DNSName
& domain
, const std :: string
& ips
)
826 vector
< ComboAddress
> masters
;
827 vector
< string
> parts
;
828 stringtok ( parts
, ips
, " \t ;," );
829 for ( const auto & ip
: parts
)
830 masters
. push_back ( ComboAddress ( ip
, 53 ));
832 return genChangeDomain ( domain
, [& masters
]( DomainInfo
& di
) {
833 di
. masters
= masters
;
837 bool LMDBBackend :: createDomain ( const DNSName
& domain
)
839 return createDomain ( domain
, "NATIVE" , "" , "" );
842 bool LMDBBackend :: createDomain ( const DNSName
& domain
, const string
& type
, const string
& masters
, const string
& account
)
846 auto txn
= d_tdomains
-> getRWTransaction ();
847 if ( txn
. get
< 0 >( domain
, di
)) {
848 throw DBException ( "Domain '" + domain
. toLogString ()+ "' exists already" );
852 if ( pdns_iequals ( type
, "master" ))
853 di
. kind
= DomainInfo :: Master
;
854 else if ( pdns_iequals ( type
, "slave" ))
855 di
. kind
= DomainInfo :: Slave
;
856 else if ( pdns_iequals ( type
, "native" ))
857 di
. kind
= DomainInfo :: Native
;
859 throw DBException ( "Unable to create domain of unknown type '" + type
+ "'" );
860 di
. account
= account
;
868 void LMDBBackend :: getAllDomains ( vector
< DomainInfo
> * domains
, bool include_disabled
)
870 compoundOrdername co
;
873 auto txn
= d_tdomains
-> getROTransaction ();
874 for ( auto iter
= txn
. begin (); iter
!= txn
. end (); ++ iter
) {
876 di
. id
= iter
. getID ();
878 auto txn2
= getRecordsROTransaction ( iter
. getID ());
879 if (! txn2
-> txn
-> get ( txn2
-> db
-> dbi
, co ( di
. id
, g_rootdnsname
, QType :: SOA
), val
)) {
880 DNSResourceRecord rr
;
881 serFromString ( val
. get
< string_view
>(), rr
);
883 if ( rr
. content
. size () >= 5 * sizeof ( uint32_t )) {
884 uint32_t serial
= * reinterpret_cast < uint32_t *>(& rr
. content
[ rr
. content
. size () - ( 5 * sizeof ( uint32_t ))]);
885 di
. serial
= ntohl ( serial
);
887 } else if (! include_disabled
) {
890 domains
-> push_back ( di
);
894 void LMDBBackend :: getUnfreshSlaveInfos ( vector
< DomainInfo
>* domains
)
896 // cout<<"Start of getUnfreshSlaveInfos"<<endl;
898 auto txn
= d_tdomains
-> getROTransaction ();
900 time_t now
= time ( 0 );
901 for ( auto iter
= txn
. begin (); iter
!= txn
. end (); ++ iter
) {
902 if ( iter
-> kind
!= DomainInfo :: Slave
)
905 auto txn2
= getRecordsROTransaction ( iter
. getID ());
906 compoundOrdername co
;
909 if (! txn2
-> txn
-> get ( txn2
-> db
-> dbi
, co ( iter
. getID (), g_rootdnsname
, QType :: SOA
), val
)) {
910 DNSResourceRecord rr
;
911 serFromString ( val
. get
< string_view
>(), rr
);
914 memcpy (& st
, & rr
. content
[ rr
. content
. size ()- sizeof ( soatimes
)], sizeof ( soatimes
));
916 if (( time_t )( iter
-> last_check
+ ntohl ( st
. refresh
)) >= now
) { // still fresh
917 continue ; // try next domain
919 // cout << di.last_check <<" + " <<sdata.refresh<<" > = " << now << "\n";
920 serial
= ntohl ( st
. serial
);
923 // cout << "Could not find SOA for "<<iter->zone<<" with id "<<iter.getID()<<endl;
927 di
. id
= iter
. getID ();
930 domains
-> push_back ( di
);
932 // cout<<"END of getUnfreshSlaveInfos"<<endl;
935 bool LMDBBackend :: getAllDomainMetadata ( const DNSName
& name
, std :: map
< std :: string
, std :: vector
< std :: string
> >& meta
)
938 auto txn
= d_tmeta
-> getROTransaction ();
939 auto range
= txn
. equal_range
< 0 >( name
);
941 for ( auto & iter
= range
. first
; iter
!= range
. second
; ++ iter
) {
942 meta
[ iter
-> key
]. push_back ( iter
-> value
);
947 bool LMDBBackend :: setDomainMetadata ( const DNSName
& name
, const std :: string
& kind
, const std :: vector
< std :: string
>& meta
)
949 auto txn
= d_tmeta
-> getRWTransaction ();
951 auto range
= txn
. equal_range
< 0 >( name
);
953 for ( auto & iter
= range
. first
; iter
!= range
. second
; ++ iter
) {
954 if ( iter
-> key
== kind
)
958 for ( const auto & m
: meta
) {
959 DomainMeta dm
{ name
, kind
, m
};
967 bool LMDBBackend :: getDomainKeys ( const DNSName
& name
, std :: vector
< KeyData
>& keys
)
969 auto txn
= d_tkdb
-> getROTransaction ();
970 auto range
= txn
. equal_range
< 0 >( name
);
971 for ( auto & iter
= range
. first
; iter
!= range
. second
; ++ iter
) {
972 KeyData kd
{ iter
-> content
, iter
. getID (), iter
-> flags
, iter
-> active
};
979 bool LMDBBackend :: removeDomainKey ( const DNSName
& name
, unsigned int id
)
981 auto txn
= d_tkdb
-> getRWTransaction ();
983 if ( txn
. get ( id
, kdb
)) {
984 if ( kdb
. domain
== name
) {
990 // cout << "??? wanted to remove domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
994 bool LMDBBackend :: addDomainKey ( const DNSName
& name
, const KeyData
& key
, int64_t & id
)
996 auto txn
= d_tkdb
-> getRWTransaction ();
997 KeyDataDB kdb
{ name
, key
. content
, key
. flags
, key
. active
};
1004 bool LMDBBackend :: activateDomainKey ( const DNSName
& name
, unsigned int id
)
1006 auto txn
= d_tkdb
-> getRWTransaction ();
1008 if ( txn
. get ( id
, kdb
)) {
1009 if ( kdb
. domain
== name
) {
1010 txn
. modify ( id
, []( KeyDataDB
& kdbarg
)
1012 kdbarg
. active
= true ;
1019 // cout << "??? wanted to activate domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
1023 bool LMDBBackend :: deactivateDomainKey ( const DNSName
& name
, unsigned int id
)
1025 auto txn
= d_tkdb
-> getRWTransaction ();
1027 if ( txn
. get ( id
, kdb
)) {
1028 if ( kdb
. domain
== name
) {
1029 txn
. modify ( id
, []( KeyDataDB
& kdbarg
)
1031 kdbarg
. active
= false ;
1037 // cout << "??? wanted to activate domain key for domain "<<name<<" with id "<<id<<", could not find it"<<endl;
1041 bool LMDBBackend :: getBeforeAndAfterNamesAbsolute ( uint32_t id
, const DNSName
& qname
, DNSName
& unhashed
, DNSName
& before
, DNSName
& after
)
1043 // cout << __PRETTY_FUNCTION__<< ": "<<id <<", "<<qname << " " << unhashed<<endl;
1046 if (! d_tdomains
-> getROTransaction (). get ( id
, di
)) {
1047 // domain does not exist, tough luck
1050 // cout <<"Zone: "<<di.zone<<endl;
1052 compoundOrdername co
;
1053 auto txn
= getRecordsROTransaction ( id
);
1055 auto cursor
= txn
-> txn
-> getCursor ( txn
-> db
-> dbi
);
1058 DNSResourceRecord rr
;
1060 string matchkey
= co ( id
, qname
, QType :: NSEC3
);
1061 if ( cursor
. lower_bound ( matchkey
, key
, val
)) {
1062 // this is beyond the end of the database
1063 // cout << "Beyond end of database!" << endl;
1064 cursor
. last ( key
, val
);
1067 if ( co
. getDomainID ( key
. get
< StringView
>()) != id
) {
1068 //cout<<"Last record also not part of this zone!"<<endl;
1069 // this implies something is wrong in the database, nothing we can do
1073 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1074 serFromString ( val
. get
< StringView
>(), rr
);
1075 if (! rr
. ttl
) // the kind of NSEC3 we need
1078 if ( cursor
. prev ( key
, val
)) {
1079 // hit beginning of database, again means something is wrong with it
1083 before
= co
. getQName ( key
. get
< StringView
>());
1084 unhashed
= DNSName ( rr
. content
. c_str (), rr
. content
. size (), 0 , false ) + di
. zone
;
1086 // now to find after .. at the beginning of the zone
1087 if ( cursor
. lower_bound ( co ( id
), key
, val
)) {
1088 // cout<<"hit end of zone find when we shouldn't"<<endl;
1092 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1093 serFromString ( val
. get
< StringView
>(), rr
);
1098 if ( cursor
. next ( key
, val
) || co
. getDomainID ( key
. get
< StringView
>()) != id
) {
1099 // cout<<"hit end of zone or database when we shouldn't"<<endl;
1103 after
= co
. getQName ( key
. get
< StringView
>());
1104 // cout<<"returning: before="<<before<<", after="<<after<<", unhashed: "<<unhashed<<endl;
1108 // cout<<"Ended up at "<<co.getQName(key.get<StringView>()) <<endl;
1110 before
= co
. getQName ( key
. get
< StringView
>());
1111 if ( before
== qname
) {
1112 // cout << "Ended up on exact right node" << endl;
1113 before
= co
. getQName ( key
. get
< StringView
>());
1114 // unhashed should be correct now, maybe check?
1115 if ( cursor
. next ( key
, val
)) {
1116 // xxx should find first hash now
1118 if ( cursor
. lower_bound ( co ( id
), key
, val
)) {
1119 // cout<<"hit end of zone find when we shouldn't for id "<<id<< __LINE__<<endl;
1123 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1124 serFromString ( val
. get
< StringView
>(), rr
);
1129 if ( cursor
. next ( key
, val
) || co
. getDomainID ( key
. get
< StringView
>()) != id
) {
1130 // cout<<"hit end of zone or database when we shouldn't" << __LINE__<<endl;
1134 after
= co
. getQName ( key
. get
< StringView
>());
1135 // cout<<"returning: before="<<before<<", after="<<after<<", unhashed: "<<unhashed<<endl;
1140 // cout <<"Going backwards to find 'before'"<<endl;
1143 if ( co
. getQName ( key
. get
< StringView
>()). canonCompare ( qname
) && co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1144 // cout<<"Potentially stopping traverse at "<< co.getQName(key.get<StringView>()) <<", " << (co.getQName(key.get<StringView>()).canonCompare(qname))<<endl;
1145 // cout<<"qname = "<<qname<<endl;
1146 // cout<<"here = "<<co.getQName(key.get<StringView>())<<endl;
1147 serFromString ( val
. get
< StringView
>(), rr
);
1152 if ( cursor
. prev ( key
, val
) || co
. getDomainID ( key
. get
< StringView
>()) != id
) {
1153 // cout <<"XXX Hit *beginning* of zone or database"<<endl;
1154 // this can happen, must deal with it
1155 // should now find the last hash of the zone
1157 if ( cursor
. lower_bound ( co ( id
+ 1 ), key
, val
)) {
1158 // cout << "Could not find the next higher zone, going to the end of the database then"<<endl;
1159 cursor
. last ( key
, val
);
1162 cursor
. prev ( key
, val
);
1165 if ( co
. getDomainID ( key
. get
< StringView
>()) != id
) {
1166 //cout<<"Last record also not part of this zone!"<<endl;
1167 // this implies something is wrong in the database, nothing we can do
1171 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1172 serFromString ( val
. get
< StringView
>(), rr
);
1173 if (! rr
. ttl
) // the kind of NSEC3 we need
1176 if ( cursor
. prev ( key
, val
)) {
1177 // hit beginning of database, again means something is wrong with it
1181 before
= co
. getQName ( key
. get
< StringView
>());
1182 unhashed
= DNSName ( rr
. content
. c_str (), rr
. content
. size (), 0 , false ) + di
. zone
;
1183 // cout <<"Should still find 'after'!"<<endl;
1184 // for 'after', we need to find the first hash of this zone
1186 if ( cursor
. lower_bound ( co ( id
), key
, val
)) {
1187 // cout<<"hit end of zone find when we shouldn't"<<endl;
1188 // means database is wrong, nothing we can do
1192 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1193 serFromString ( val
. get
< StringView
>(), rr
);
1198 if ( cursor
. next ( key
, val
)) {
1199 // means database is wrong, nothing we can do
1200 // cout<<"hit end of zone when we shouldn't 2"<<endl;
1204 after
= co
. getQName ( key
. get
< StringView
>());
1207 // cout<<"returning: before="<<before<<", after="<<after<<", unhashed: "<<unhashed<<endl;
1212 before
= co
. getQName ( key
. get
< StringView
>());
1213 unhashed
= DNSName ( rr
. content
. c_str (), rr
. content
. size (), 0 , false ) + di
. zone
;
1214 // cout<<"Went backwards, found "<<before<<endl;
1215 // return us to starting point
1217 cursor
. next ( key
, val
);
1219 // cout<<"Now going forward"<<endl;
1220 for ( int count
= 0 ;;++ count
) {
1221 if (( count
&& cursor
. next ( key
, val
)) || co
. getDomainID ( key
. get
< StringView
>()) != id
) {
1222 // cout <<"Hit end of database or zone, finding first hash then in zone "<<id<<endl;
1223 if ( cursor
. lower_bound ( co ( id
), key
, val
)) {
1224 // cout<<"hit end of zone find when we shouldn't"<<endl;
1225 // means database is wrong, nothing we can do
1229 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1230 serFromString ( val
. get
< StringView
>(), rr
);
1235 if ( cursor
. next ( key
, val
)) {
1236 // means database is wrong, nothing we can do
1237 // cout<<"hit end of zone when we shouldn't 2"<<endl;
1240 // cout << "Next.. "<<endl;
1242 after
= co
. getQName ( key
. get
< StringView
>());
1244 // cout<<"returning: before="<<before<<", after="<<after<<", unhashed: "<<unhashed<<endl;
1248 // cout<<"After "<<co.getQName(key.get<StringView>()) <<endl;
1249 if ( co
. getQType ( key
. get
< StringView
>()) == QType :: NSEC3
) {
1250 serFromString ( val
. get
< StringView
>(), rr
);
1256 after
= co
. getQName ( key
. get
< StringView
>());
1257 // cout<<"returning: before="<<before<<", after="<<after<<", unhashed: "<<unhashed<<endl;
1261 bool LMDBBackend :: getBeforeAndAfterNames ( uint32_t id
, const DNSName
& zonenameU
, const DNSName
& qname
, DNSName
& before
, DNSName
& after
)
1263 DNSName zonename
= zonenameU
. makeLowerCase ();
1264 // cout << __PRETTY_FUNCTION__<< ": "<<id <<", "<<zonename << ", '"<<qname<<"'"<<endl;
1266 auto txn
= getRecordsROTransaction ( id
);
1267 compoundOrdername co
;
1268 DNSName qname2
= qname
. makeRelative ( zonename
);
1269 string matchkey
= co ( id
, qname2
);
1270 auto cursor
= txn
-> txn
-> getCursor ( txn
-> db
-> dbi
);
1272 // cout<<"Lower_bound for "<<qname2<<endl;
1273 if ( cursor
. lower_bound ( matchkey
, key
, val
)) {
1274 // cout << "Hit end of database, bummer"<<endl;
1275 cursor
. last ( key
, val
);
1276 if ( co
. getDomainID ( key
. get
< string_view
>()) == id
) {
1277 before
= co
. getQName ( key
. get
< string_view
>()) + zonename
;
1281 // cout << "We were at end of database, but this zone is not there?!"<<endl;
1284 // cout<<"Cursor is at "<<co.getQName(key.get<string_view>()) <<", in zone id "<<co.getDomainID(key.get<string_view>())<< endl;
1286 if ( co
. getQType ( key
. get
< string_view
>()). getCode () && co
. getDomainID ( key
. get
< string_view
>()) == id
&& co
. getQName ( key
. get
< string_view
>()) == qname2
) { // don't match ENTs
1287 // cout << "Had an exact match!"<<endl;
1288 before
= qname2
+ zonename
;
1291 rc
= cursor
. next ( key
, val
);
1294 if ( co
. getDomainID ( key
. get
< string_view
>()) == id
&& key
. get
< StringView
>(). rfind ( matchkey
, 0 )== 0 )
1296 DNSResourceRecord rr
;
1297 serFromString ( val
. get
< StringView
>(), rr
);
1298 if ( co
. getQType ( key
. get
< string_view
>()). getCode () && ( rr
. auth
|| co
. getQType ( key
. get
< string_view
>()). getCode () == QType :: NS
))
1301 if ( rc
|| co
. getDomainID ( key
. get
< string_view
>()) != id
) {
1302 // cout << "We hit the end of the zone or database. 'after' is apex" << endl;
1306 after
= co
. getQName ( key
. get
< string_view
>()) + zonename
;
1311 if ( co
. getDomainID ( key
. get
< string_view
>()) != id
) {
1312 // cout << "Ended up in next zone, 'after' is zonename" <<endl;
1314 // cout << "Now hunting for previous" << endl;
1317 rc
= cursor
. prev ( key
, val
);
1319 // cout<<"Reversed into zone, but got not found from lmdb" <<endl;
1323 if ( co
. getDomainID ( key
. get
< string_view
>()) != id
) {
1324 // cout<<"Reversed into zone, but found wrong zone id " << co.getDomainID(key.get<string_view>()) << " != "<<id<<endl;
1325 // "this can't happen"
1328 DNSResourceRecord rr
;
1329 serFromString ( val
. get
< StringView
>(), rr
);
1330 if ( co
. getQType ( key
. get
< string_view
>()). getCode () && ( rr
. auth
|| co
. getQType ( key
. get
< string_view
>()). getCode () == QType :: NS
))
1334 before
= co
. getQName ( key
. get
< string_view
>()) + zonename
;
1335 // cout<<"Found: "<< before<<endl;
1339 // cout <<"We ended up after "<<qname<<", on "<<co.getQName(key.get<string_view>())<<endl;
1343 DNSResourceRecord rr
;
1344 serFromString ( val
. get
< StringView
>(), rr
);
1345 if ( co
. getQType ( key
. get
< string_view
>()). getCode () && ( rr
. auth
|| co
. getQType ( key
. get
< string_view
>()). getCode () == QType :: NS
)) {
1346 after
= co
. getQName ( key
. get
< string_view
>()) + zonename
;
1347 // cout <<"Found auth ("<<rr.auth<<") or an NS record "<<after<<", type: "<<co.getQType(key.get<string_view>()).getName()<<", ttl = "<<rr.ttl<<endl;
1348 // cout << makeHexDump(val.get<string>()) << endl;
1351 // cout <<" oops, " << co.getQName(key.get<string_view>()) << " was not auth "<<rr.auth<< " type=" << rr.qtype.getName()<<" or NS, so need to skip ahead a bit more" << endl;
1352 int rc
= cursor
. next ( key
, val
);
1355 if ( rc
|| co
. getDomainID ( key
. get
< string_view
>()) != id
) {
1356 // cout << " oops, hit end of database or zone. This means after is apex" <<endl;
1361 // go back to where we were
1363 cursor
. prev ( key
, val
);
1366 int rc
= cursor
. prev ( key
, val
);
1367 if ( rc
|| co
. getDomainID ( key
. get
< string_view
>()) != id
) {
1368 // XX I don't think this case can happen
1369 // cout << "We hit the beginning of the zone or database.. now what" << endl;
1372 before
= co
. getQName ( key
. get
< string_view
>()) + zonename
;
1373 DNSResourceRecord rr
;
1374 serFromString ( val
. get
< string_view
>(), rr
);
1375 // cout<<"And before to "<<before<<", auth = "<<rr.auth<<endl;
1376 if ( co
. getQType ( key
. get
< string_view
>()). getCode () && ( rr
. auth
|| co
. getQType ( key
. get
< string_view
>()) == QType :: NS
))
1378 // cout << "Oops, that was wrong, go back one more"<<endl;
1385 bool LMDBBackend :: updateDNSSECOrderNameAndAuth ( uint32_t domain_id
, const DNSName
& qname
, const DNSName
& ordername
, bool auth
, const uint16_t qtype
)
1387 // cout << __PRETTY_FUNCTION__<< ": "<< domain_id <<", '"<<qname <<"', '"<<ordername<<"', "<<auth<< ", " << qtype << endl;
1388 shared_ptr
< RecordsRWTransaction
> txn
;
1389 bool needCommit
= false ;
1390 if ( d_rwtxn
&& d_transactiondomainid
== domain_id
) {
1392 // cout<<"Reusing open transaction"<<endl;
1395 // cout<<"Making a new RW txn for " << __PRETTY_FUNCTION__ <<endl;
1396 txn
= getRecordsRWTransaction ( domain_id
);
1401 if (! d_tdomains
-> getROTransaction (). get ( domain_id
, di
)) {
1402 // cout<<"Could not find domain_id "<<domain_id <<endl;
1406 DNSName rel
= qname
. makeRelative ( di
. zone
);
1408 compoundOrdername co
;
1409 string matchkey
= co ( domain_id
, rel
);
1411 auto cursor
= txn
-> txn
-> getCursor ( txn
-> db
-> dbi
);
1413 if ( cursor
. lower_bound ( matchkey
, key
, val
)) {
1414 // cout << "Could not find anything"<<endl;
1418 bool hasOrderName
= ! ordername
. empty ();
1419 bool needNSEC3
= hasOrderName
;
1421 for (; key
. get
< StringView
>(). rfind ( matchkey
, 0 ) == 0 ; ) {
1422 DNSResourceRecord rr
;
1423 rr
. qtype
= co
. getQType ( key
. get
< StringView
>());
1425 if ( rr
. qtype
!= QType :: NSEC3
) {
1426 serFromString ( val
. get
< StringView
>(), rr
);
1427 if (! needNSEC3
&& qtype
!= QType :: ANY
) {
1428 needNSEC3
= ( rr
. disabled
&& QType ( qtype
) != rr
. qtype
);
1431 if (( qtype
== QType :: ANY
|| QType ( qtype
) == rr
. qtype
) && ( rr
. disabled
!= hasOrderName
|| rr
. auth
!= auth
)) {
1433 rr
. disabled
= hasOrderName
;
1434 string repl
= serToString ( rr
);
1435 cursor
. put ( key
, repl
);
1439 if ( cursor
. next ( key
, val
))
1444 DNSResourceRecord rr
;
1445 matchkey
= co ( domain_id
, rel
, QType :: NSEC3
);
1446 if (! txn
-> txn
-> get ( txn
-> db
-> dbi
, matchkey
, val
)) {
1447 serFromString ( val
. get
< string_view
>(), rr
);
1450 if ( hasOrderName
&& rr
. content
!= ordername
. toDNSStringLC ()) {
1457 txn
-> txn
-> del ( txn
-> db
-> dbi
, co ( domain_id
, DNSName ( rr
. content
. c_str (), rr
. content
. size (), 0 , false ), QType :: NSEC3
));
1458 txn
-> txn
-> del ( txn
-> db
-> dbi
, matchkey
);
1464 if ( hasOrderName
&& del
) {
1465 matchkey
= co ( domain_id
, rel
, QType :: NSEC3
);
1469 rr
. content
= rel
. toDNSStringLC ();
1471 string str
= serToString ( rr
);
1472 txn
-> txn
-> put ( txn
-> db
-> dbi
, co ( domain_id
, ordername
, QType :: NSEC3
), str
);
1474 rr
. content
= ordername
. toDNSStringLC ();
1475 str
= serToString ( rr
);
1476 txn
-> txn
-> put ( txn
-> db
-> dbi
, matchkey
, str
); // 2
1484 bool LMDBBackend :: updateEmptyNonTerminals ( uint32_t domain_id
, set
< DNSName
>& insert
, set
< DNSName
>& erase
, bool remove
)
1486 // cout << __PRETTY_FUNCTION__<< ": "<< domain_id << ", insert.size() "<<insert.size()<<", "<<erase.size()<<", " <<remove<<endl;
1488 bool needCommit
= false ;
1489 shared_ptr
< RecordsRWTransaction
> txn
;
1490 if ( d_rwtxn
&& d_transactiondomainid
== domain_id
) {
1492 // cout<<"Reusing open transaction"<<endl;
1495 // cout<<"Making a new RW txn for delete domain"<<endl;
1496 txn
= getRecordsRWTransaction ( domain_id
);
1501 // if remove is set, all ENTs should be removed & nothing else should be done
1503 deleteDomainRecords (* txn
, domain_id
, 0 );
1507 auto rotxn
= d_tdomains
-> getROTransaction ();
1508 if (! rotxn
. get ( domain_id
, di
)) {
1509 // cout <<"No such domain with id "<<domain_id<<endl;
1512 compoundOrdername co
;
1513 for ( const auto & n
: insert
) {
1514 DNSResourceRecord rr
;
1515 rr
. qname
= n
. makeRelative ( di
. zone
);
1519 std :: string ser
= serToString ( rr
);
1521 txn
-> txn
-> put ( txn
-> db
-> dbi
, co ( domain_id
, rr
. qname
, 0 ), ser
);
1523 DNSResourceRecord rr2
;
1524 serFromString ( ser
, rr2
);
1526 // cout <<" +"<<n<<endl;
1528 for ( auto n
: erase
) {
1529 // cout <<" -"<<n<<endl;
1530 n
. makeUsRelative ( di
. zone
);
1531 txn
-> txn
-> del ( txn
-> db
-> dbi
, co ( domain_id
, n
, 0 ));
1540 bool LMDBBackend :: getTSIGKey ( const DNSName
& name
, DNSName
* algorithm
, string
* content
)
1542 auto txn
= d_ttsig
-> getROTransaction ();
1545 if (! txn
. get
< 0 >( name
, tk
))
1548 * algorithm
= tk
. algorithm
;
1554 // this deletes an old key if it has the same algorithm
1555 bool LMDBBackend :: setTSIGKey ( const DNSName
& name
, const DNSName
& algorithm
, const string
& content
)
1557 auto txn
= d_ttsig
-> getRWTransaction ();
1559 for ( auto range
= txn
. equal_range
< 0 >( name
); range
. first
!= range
. second
; ++ range
. first
) {
1560 if ( range
. first
-> algorithm
== algorithm
)
1566 tk
. algorithm
= algorithm
;
1574 bool LMDBBackend :: deleteTSIGKey ( const DNSName
& name
)
1576 auto txn
= d_ttsig
-> getRWTransaction ();
1579 for ( auto range
= txn
. equal_range
< 0 >( name
); range
. first
!= range
. second
; ++ range
. first
) {
1585 bool LMDBBackend :: getTSIGKeys ( std :: vector
< struct TSIGKey
> & keys
)
1587 auto txn
= d_ttsig
-> getROTransaction ();
1590 for ( auto iter
= txn
. begin (); iter
!= txn
. end (); ++ iter
) {
1591 keys
. push_back (* iter
);
1599 class LMDBFactory
: public BackendFactory
1602 LMDBFactory () : BackendFactory ( "lmdb" ) {}
1603 void declareArguments ( const string
& suffix
= "" )
1605 declare ( suffix
, "filename" , "Filename for lmdb" , "./pdns.lmdb" );
1606 declare ( suffix
, "sync-mode" , "Synchronisation mode: nosync, nometasync, mapasync, sync" , "mapasync" );
1607 // there just is no room for more on 32 bit
1608 declare ( suffix
, "shards" , "Records database will be split into this number of shards" , ( sizeof ( long ) == 4 ) ? "2" : "64" );
1610 DNSBackend
* make ( const string
& suffix
= "" )
1612 return new LMDBBackend ( suffix
);
1626 BackendMakers (). report ( new LMDBFactory
);
1627 g_log
<< Logger :: Info
<< "[lmdbbackend] This is the lmdb backend version " VERSION
1628 #ifndef REPRODUCIBLE
1629 << " (" __DATE__
" " __TIME__
")"
1631 << " reporting" << endl
;
1635 static LMDBLoader randomLoader
;