return true;
}
-/* This is a subclass of DNSBackend that, assuming you have your zones reversed
- * and stored in an ordered fashion, will be able to look up SOA's much quicker
- * than the DNSBackend code. The normal case for a SOA that exists is 1 backend
- * query no matter how much the depth (although if there are sub-SOA's then
- * this could require one or two more queries). The normal case for an SOA that
- * does not exist is 2 or 3 queries depending on the system, although this will
- * be reduced if the negative cache is active.
- *
- * The subclass MUST implement bool getAuthZone(string &reversed_zone_name)
- * which, given a reversed zone name will return false if there was some sort
- * of error (eg no record found as top of database was hit, lookup issues),
- * otherwise returns true and sets reversed_zone_name to be the exact entry
- * found, otherwise the entry directly preceding where it would be.
- *
- * The subclass MUST implement getAuthData( const string &rev_zone_name, SOAData *soa )
- * which is basically the same as getSOA() but is called with the reversed zone name
- */
-enum {
- GET_AUTH_NEG_DONTCACHE, // not found but don't cache this fact
- GET_AUTH_NEG_CACHE, // not found and negcache this
- GET_AUTH_SUCCESS, // entry found
-};
-
-#undef PC
-extern PacketCache PC;
-
-#if 0
-#undef DLOG
-#define DLOG(x) x
-#endif
-
-// XXX DNSName pain, should be DNSName native.
-static bool add_to_negcache( const string &zone ) {
- static int negqueryttl=::arg().asNum("negquery-cache-ttl");
- // add the zone to the negative query cache and return false
- if(negqueryttl) {
- DLOG(L<<Logger::Error<<"Adding to neg qcache: " << zone<<endl);
- PC.insert(DNSName(zone), QType(QType::SOA), PacketCache::QUERYCACHE, "", negqueryttl, 0);
- }
- return false;
-}
-
-// XXX DNSName Pain, this should be DNSName native! vvvvvvvvvvvvvv
-inline int DNSReversedBackend::_getAuth(DNSPacket *p, SOAData *soa, const string &inZone, const string &querykey, const int best_match_len) {
- static int negqueryttl=::arg().asNum("negquery-cache-ttl");
-
- DLOG(L<<Logger::Error<<"SOA Query: " <<querykey<<endl);
-
- /* Got a match from a previous backend that was longer than this - no need
- * to continue. This is something of an optimization as we would hit the
- * similar test below in any cases that this was hit, although we would run
- * the risk of something being added to the neg-querycache that may
- * interfear with future queries
- */
- if( best_match_len >= (int)querykey.length() ) {
- DLOG(L<<Logger::Error<<"Best match was better from a different client"<<endl);
- return GET_AUTH_NEG_DONTCACHE;
- }
-
- /* Look up in the negative querycache to see if we have already tried and
- * failed to look up this zone */
- if( negqueryttl ) {
- string content;
- bool ret = PC.getEntry( DNSName(inZone), QType(QType::SOA), PacketCache::QUERYCACHE, content, 0 );
- if( ret && content.empty() ) {
- DLOG(L<<Logger::Error<<"Found in neg qcache: " << inZone << ":" << content << ":" << ret << ":"<<endl);
- return GET_AUTH_NEG_DONTCACHE;
- }
- }
-
- /* Find the SOA entry on- or before- the position that we want in the b-tree */
- string foundkey = querykey;
- if( !getAuthZone( foundkey ) )
- return GET_AUTH_NEG_CACHE;
-
- DLOG(L<<Logger::Error<<"Queried: " << querykey << " and found record: " <<foundkey<<endl);
-
- // Got a match from a previous backend that was longer than this - no need
- // to continue.
- if( best_match_len && best_match_len >= (int) foundkey.length() ) {
- DLOG(L<<Logger::Error<<"Best match was better from a different client"<<endl);
- return GET_AUTH_NEG_DONTCACHE;
- }
-
- // Found record successfully now, fill in the data.
- if( getAuthData( *soa, p ) ) {
- /* all the keys are reversed. rather than reversing them again it is
- * presumably quicker to just substring the zone down to size */
- soa->qname = DNSName(inZone.substr( inZone.length() - foundkey.length(), string::npos ));
-
- DLOG(L<<Logger::Error<<"Successfully got record: " <<foundkey << " : " << querykey.substr( 0, foundkey.length() ) << " : " << soa->qname<<endl);
-
- return GET_AUTH_SUCCESS;
- }
-
- return GET_AUTH_NEG_CACHE;
-}
-
-bool DNSReversedBackend::getAuth(DNSPacket *p, SOAData *soa, const DNSName &inZone, const int best_match_len) {
- // Reverse the lowercased query string
- string zone = toLower(inZone.toStringNoDot());
- string querykey = labelReverse(zone);
-
- int ret = _getAuth( p, soa, inZone.toStringNoDot(), querykey, best_match_len );
-
- /* If this is disabled then we would just cache the tree structure not the
- * leaves which should give the best performance and a nice small negcache
- * size
- */
- if( ret == GET_AUTH_NEG_CACHE )
- add_to_negcache( inZone.toStringNoDot() );
-
- return ret == GET_AUTH_SUCCESS;
-}
-
-/* getAuthData() is very similar to getSOA() so implement a default getSOA
- * based on that. This will only be called very occasionally for example during
- * an AXFR */
-bool DNSReversedBackend::_getSOA(const string &querykey, SOAData &soa, DNSPacket *p)
-{
- string searchkey( querykey );
-
- if( !getAuthZone( searchkey ) )
- return false;
-
- DLOG(L<<Logger::Error<<"search key " << searchkey << " query key " << querykey<<endl);
-
- if( querykey.compare( searchkey ) != 0 )
- return false;
-
- return getAuthData( soa, p );
-}
-
-bool DNSReversedBackend::getSOA(const DNSName &inZone, SOAData &soa, DNSPacket *p)
-{
- // prepare the query string
- string zone = toLower( inZone.toStringNoDot() );
- string querykey = labelReverse( zone );
-
- if( !_getSOA( querykey, soa, p ) )
- return false;
-
- soa.qname = inZone;
- return true;
-}
-
void fillSOAData(const string &content, SOAData &data)
{
// content consists of fields separated by spaces:
string d_prefix;
};
-class DNSReversedBackend : public DNSBackend {
- public:
- /* Given rev_zone (the reversed name of the zone we are looking for the
- * SOA record for), return the equivalent of
- * SELECT name
- * FROM soa_records
- * WHERE name <= rev_zone
- * ORDER BY name DESC
- *
- * ie we want either an exact hit on the record, or the immediately
- * preceding record when sorted lexographically.
- *
- * Return true if something has been found, false if not
- */
- virtual bool getAuthZone( string &rev_zone ) { return false; }; // Must be overridden
-
- /* Once the record has been found, this will be called to get the data
- * associated with the record so the backend can set up soa.
- * soa->qname does not need to be set. Return false if
- * there is a problem getting the data.
- * */
- virtual bool getAuthData( SOAData &soa, DNSPacket *p=0) { return false; }; // Must be overridden
-
- virtual bool getAuth(DNSPacket *p, SOAData *soa, const DNSName &inZone, const int best_match_len) override;
- inline int _getAuth(DNSPacket *p, SOAData *soa, const string &inZone, const string &querykey, const int best_match_len);
-
- /* Only called for stuff like signing or AXFR transfers */
- bool _getSOA(const string &rev_zone, SOAData &soa, DNSPacket *p);
- virtual bool getSOA(const DNSName &inZone, SOAData &soa, DNSPacket *p) override;
-};
-
class BackendFactory
{
public: