From: Grégory Oestreicher Date: Fri, 13 Oct 2017 20:35:09 +0000 (+0200) Subject: Add support for per-record data X-Git-Tag: dnsdist-1.3.1~167^2~4 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=521a08fcc58cb6fe485a910b60b18ce26892d2d3;p=pdns Add support for per-record data This allows to specify per RR set TTL, auth status and ordername. --- diff --git a/modules/ldapbackend/ldapbackend.cc b/modules/ldapbackend/ldapbackend.cc index b6b4687d6..9a5441844 100644 --- a/modules/ldapbackend/ldapbackend.cc +++ b/modules/ldapbackend/ldapbackend.cc @@ -201,6 +201,57 @@ void LdapBackend::extract_entry_results( const DNSName& domain, const DNSResult& local_result.qtype = qt; local_result.qname = domain; local_result.value = value; + local_result.auth = true; + + // Now let's see if we have some PDNS record data + + // TTL + if ( d_result.count( "PdnsRecordTTL" ) && !d_result["PdnsRecordTTL"].empty() ) { + for ( const auto& rdata : d_result["PdnsRecordTTL"] ) { + std::string qtype; + std::size_t pos = rdata.find_first_of( '|', 0 ); + if ( pos == std::string::npos ) + continue; + + qtype = rdata.substr( 0, pos ); + if ( qtype != QType( local_result.qtype ).getName() ) + continue; + + local_result.ttl = pdns_stou( rdata.substr( pos + 1 ) ); + } + } + + // Not authoritative + if ( d_result.count( "PdnsRecordNoAuth" ) && !d_result["PdnsRecordNoAuth"].empty() ) { + for ( const auto& rdata : d_result["PdnsRecordNoAuth"] ) { + if ( rdata == QType( local_result.qtype ).getName() ) + local_result.auth = false; + } + } + + // Ordername + if ( d_result.count( "PdnsRecordOrdername" ) && !d_result["PdnsRecordOrdername"].empty() ) { + std::string defaultOrdername; + + for ( const auto& rdata : d_result["PdnsRecordOrdername"] ) { + std::string qtype; + std::size_t pos = rdata.find_first_of( '|', 0 ); + if ( pos == std::string::npos ) { + // This is the default ordername for all records in this entry + defaultOrdername = rdata; + continue; + } + + qtype = rdata.substr( 0, pos ); + if ( qtype != QType( local_result.qtype ).getName() ) + continue; + + local_result.ordername = rdata.substr( pos + 1 ); + } + + if ( local_result.ordername.empty() && !defaultOrdername.empty() ) + local_result.ordername = defaultOrdername; + } d_results_cache.push_back( local_result ); } diff --git a/modules/ldapbackend/ldapbackend.hh b/modules/ldapbackend/ldapbackend.hh index b4b9cd254..1fd853669 100644 --- a/modules/ldapbackend/ldapbackend.hh +++ b/modules/ldapbackend/ldapbackend.hh @@ -100,6 +100,9 @@ static const char* ldap_attrany[] = { "TYPE65226Record", "TYPE65534Record", "modifyTimestamp", + "PdnsRecordTTL", + "PdnsRecordAuth", + "PdnsRecordOrdername", NULL }; @@ -124,6 +127,8 @@ class LdapBackend : public DNSBackend uint32_t ttl; time_t lastmod; std::string value; + bool auth; + std::string ordername; }; std::list d_results_cache; diff --git a/modules/ldapbackend/native.cc b/modules/ldapbackend/native.cc index 980cfbce9..f69d78dd4 100644 --- a/modules/ldapbackend/native.cc +++ b/modules/ldapbackend/native.cc @@ -160,7 +160,7 @@ void LdapBackend::lookup_simple( const QType &qtype, const DNSName &qname, DNSPa { string filter, attr, qesc; const char** attributes = ldap_attrany + 1; // skip associatedDomain - const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL }; + const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", "PdnsRecordTTL", "PdnsRecordAuth", "PdnsRecordOrdername", NULL }; qesc = toLower( d_pldap->escape( qname.toStringRootDot() ) ); @@ -188,7 +188,7 @@ void LdapBackend::lookup_strict( const QType &qtype, const DNSName &qname, DNSPa vector parts; string filter, attr, qesc; const char** attributes = ldap_attrany + 1; // skip associatedDomain - const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL }; + const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", "PdnsRecordTTL", "PdnsRecordAuth", "PdnsRecordOrdername", NULL }; qesc = toLower( d_pldap->escape( qname.toStringRootDot() ) ); @@ -232,7 +232,7 @@ void LdapBackend::lookup_tree( const QType &qtype, const DNSName &qname, DNSPack { string filter, attr, qesc, dn; const char** attributes = ldap_attrany + 1; // skip associatedDomain - const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL }; + const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", "PdnsRecordTTL", "PdnsRecordAuth", "PdnsRecordOrdername", NULL }; vector parts; @@ -345,6 +345,7 @@ bool LdapBackend::get( DNSResourceRecord &rr ) rr.ttl = result.ttl; rr.last_modified = 0; rr.content = result.value; + rr.auth = result.auth; g_log << Logger::Debug << d_myname << " Record = qname: " << rr.qname << ", qtype: " << (rr.qtype).getName() << ", ttl: " << rr.ttl << ", content: " << rr.content << endl; return true; diff --git a/modules/ldapbackend/pdns-domaininfo.schema b/modules/ldapbackend/pdns-domaininfo.schema index 88a6cb24a..4d300e914 100644 --- a/modules/ldapbackend/pdns-domaininfo.schema +++ b/modules/ldapbackend/pdns-domaininfo.schema @@ -43,9 +43,29 @@ attributetype ( 1.3.6.1.4.1.27080.2.1.5 NAME 'PdnsDomainType' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) +attributetype ( 1.3.6.1.4.1.27080.1.11 NAME 'PdnsRecordTTL' + DESC 'TTL for a RR set. Syntax is RR type, a literal "|", TTL' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + +attributetype ( 1.3.6.1.4.1.27080.1.12 NAME 'PdnsRecordNoAuth' + DESC 'Whether or not this entry is authoritative for the RR given in this attribute. If this attribute is present then it is *NOT* for the RR in the attribute.' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + +attributetype ( 1.3.6.1.4.1.27080.1.13 NAME 'PdnsRecordOrdername' + DESC 'The ordername for the RR. Syntax is RR type, a literal "|", the ordername' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + objectclass ( 1.3.6.1.4.1.27080.2.2.1 NAME 'PdnsDomain' DESC 'PDNS domain metadata information' SUP top AUXILIARY MUST ( PdnsDomainId ) MAY ( PdnsDomainNotifiedSerial $ PdnsDomainLastCheck $ PdnsDomainMaster $ PdnsDomainType ) ) + +objectclass ( 1.3.6.1.4.1.27080.2.2.4 NAME 'PdnsRecordData' + DESC 'Additional record data for PDNS' + SUP top AUXILIARY + MAY ( PdnsRecordTTL $ PdnsRecordNoAuth $ PdnsRecordOrdername ) ) diff --git a/pdns/zone2ldap.cc b/pdns/zone2ldap.cc index 2ccf4c473..05b626ef8 100644 --- a/pdns/zone2ldap.cc +++ b/pdns/zone2ldap.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "arguments.hh" #include "bindparserclasses.hh" @@ -45,9 +46,28 @@ using std::vector; StatBag S; ArgvMap args; bool g_dnsttl; +bool g_pdnsinfo; +unsigned int g_domainid; string g_basedn; +string g_metadatadn; DNSName g_zonename; map g_objects; +map g_entries; +map g_recorddata; +map > g_recordttl; + +std::string encode_non_ascii( const std::string &input ) { + std::ostringstream out; + + for ( auto i : input ) { + if ( (unsigned char)i > 0x7F ) + out << '\\' << int( (unsigned char)i ); + else + out << i; + } + + return out.str(); +} static void callback_simple( unsigned int domain_id, const DNSName &domain, const string &qtype, const string &content, int ttl ) { @@ -61,19 +81,36 @@ static void callback_simple( unsigned int domain_id, const DNSName &domain, cons host = domain.makeRelative(g_zonename); - cout << "dn: dc="; - if( host.countLabels() ) { cout << host.toStringNoDot() << ",dc="; } - cout << g_zonename.toStringNoDot() << "," << g_basedn << endl; + if( g_pdnsinfo && qtype == "SOA" ) { + cout << "dn: ou=" << domain << "," << g_metadatadn << endl; + cout << "changetype: add" << endl; + cout << "objectclass: organizationalUnit" << endl; + cout << "ou: " << domain.toStringNoDot() << endl; + cout << endl; + } + + std::string stripped=stripDot(content); + std::string rrvalue = stripped + ((stripped.empty() || stripped[stripped.size()-1]==' ') ? "." : ""); + std::string dn = "dc="; + if( host.countLabels() ) { dn += host.toStringNoDot() + ",dc="; } + dn += g_zonename.toStringNoDot() + "," + g_basedn; + cout << "dn: " << dn << endl; if( host.countLabels() == 0 ) { host = g_zonename; } - if( !g_objects[domain] ) + if( !g_entries[dn] ) { - g_objects[domain] = true; + g_entries[dn] = true; + g_recorddata[domain] = true; cout << "changetype: add" << endl; cout << "objectclass: dnsdomain2" << endl; cout << "objectclass: domainrelatedobject" << endl; + cout << "objectclass: PdnsRecordData" << endl; + if( g_pdnsinfo && qtype == "SOA" ) { + cout << "objectclass: PdnsDomain" << endl; + cout << "PdnsDomainId: " << domain_id << endl; + } cout << "dc: " << host.toStringNoDot() << endl; if( g_dnsttl ) { cout << "dnsttl: " << ttl << endl; } cout << "associateddomain: " << domain.toStringNoDot() << endl; @@ -81,10 +118,21 @@ static void callback_simple( unsigned int domain_id, const DNSName &domain, cons else { cout << "changetype: modify" << endl; + if ( !g_recorddata[domain] ) { + g_recorddata[domain] = true; + cout << "add: objectClass" << endl; + cout << "objectClass: PdnsRecordData" << endl; + cout << "-" << endl; + } + if ( !g_recordttl.count( domain ) || !g_recordttl[domain].count( qtype ) ) { + g_recordttl[domain][qtype] = true; + cout << "add: PdnsRecordTTL" << endl; + cout << "PdnsRecordTTL: " << qtype << "|" << ttl << endl; + cout << "-" << endl; + } cout << "add: " << qtype << "Record" << endl; } - string stripped=stripDot(content); - cout << qtype << "Record: " << stripped << ((stripped.empty() || stripped[stripped.size()-1]==' ') ? "." : "") << endl << endl; + cout << qtype << "Record: " << rrvalue << endl << endl; } @@ -118,15 +166,31 @@ static void callback_tree( unsigned int domain_id, const DNSName &domain, const } + if( g_pdnsinfo && qtype == "SOA" ) { + cout << "dn: ou=" << domain << "," << g_metadatadn << endl; + cout << "changetype: add" << endl; + cout << "objectclass: organizationalUnit" << endl; + cout << "ou: " << domain.toStringNoDot() << endl; + cout << endl; + } + + std::string stripped=stripDot(content); + std::string rrvalue = stripped + ((stripped.empty() || stripped[stripped.size()-1]==' ') ? "." : ""); cout << "dn: " << "dc=" << parts[0] << "," << dn << g_basedn << endl; if( !g_objects[domain] ) { g_objects[domain] = true; + g_recorddata[domain] = true; cout << "changetype: add" << endl; cout << "objectclass: dnsdomain2" << endl; cout << "objectclass: domainrelatedobject" << endl; + cout << "objectclass: PdnsRecordData" << endl; + if( g_pdnsinfo && qtype == "SOA" ) { + cout << "objectclass: PdnsDomain" << endl; + cout << "PdnsDomainId: " << domain_id << endl; + } cout << "dc: " << parts[0] << endl; if( g_dnsttl ) { cout << "dnsttl: " << ttl << endl; } cout << "associateddomain: " << domain.toStringNoDot() << endl; @@ -134,10 +198,29 @@ static void callback_tree( unsigned int domain_id, const DNSName &domain, const else { cout << "changetype: modify" << endl; + if( g_pdnsinfo && qtype == "SOA" ) { + cout << "add: objectclass" << endl; + cout << "objectclass: PdnsDomain" << endl; + cout << "-" << endl; + cout << "add: PdnsDomainId" << endl; + cout << "PdnsDomainId: " << domain_id << endl; + cout << "-" << endl; + } + if ( !g_recorddata[domain] ) { + g_recorddata[domain] = true; + cout << "add: objectClass" << endl; + cout << "objectClass: PdnsRecordData" << endl; + cout << "-" << endl; + } + if ( !g_recordttl.count( domain ) || !g_recordttl[domain].count( qtype ) ) { + g_recordttl[domain][qtype] = true; + cout << "add: PdnsRecordTTL" << endl; + cout << "PdnsRecordTTL: " << qtype << "|" << ttl << endl; + cout << "-" << endl; + } cout << "add: " << qtype << "Record" << endl; } - string stripped=stripDot(content); - cout << qtype << "Record: " << stripped << ((stripped.empty() || stripped[stripped.size()-1]==' ') ? "." : "") << endl << endl; + cout << qtype << "Record: " << rrvalue << endl << endl; } @@ -157,11 +240,14 @@ int main( int argc, char* argv[] ) args.setSwitch( "verbose", "Verbose comments on operation" ) = "no"; args.setSwitch( "resume", "Continue after errors" ) = "no"; args.setSwitch( "dnsttl", "Add dnsttl attribute to every entry" ) = "no"; + args.setSwitch( "pdns-info", "Add the PDNS domain info attributes (this mandates setting --metadata-dn)" ) = "no"; args.set( "named-conf", "Bind 8 named.conf to parse" ) = ""; args.set( "zone-file", "Zone file to parse" ) = ""; args.set( "zone-name", "Specify a zone name if zone is set" ) = ""; args.set( "basedn", "Base DN to store objects below" ) = "ou=hosts,o=mycompany,c=de"; args.set( "layout", "How to arrange entries in the directory (simple or as tree)" ) = "simple"; + args.set( "domainid", "Domain ID of the first domain found (incremented afterwards)" ) = "1"; + args.set( "metadata-dn", "DN under which to store the domain metadata" ) = ""; args.parse( argc, argv ); @@ -193,6 +279,23 @@ int main( int argc, char* argv[] ) callback=callback_tree; } + if ( args.mustDo( "pdns-info" ) ) { + g_pdnsinfo = true; + if( args["metadata-dn"].empty() ) { + cerr << "You must set --metadata-dn when using --pdns-info" << endl; + exit( 1 ); + } + g_metadatadn = args["metadata-dn"]; + } + else { + g_pdnsinfo = false; + } + + if ( !args["domainid"].empty() ) + g_domainid = pdns_stou( args["domainid"] ); + else + g_domainid = 1; + if( !args["named-conf"].empty() ) { BP.setVerbose( args.mustDo( "verbose" ) ); @@ -208,14 +311,17 @@ int main( int argc, char* argv[] ) } try { - if( i->name != g_rootdnsname && i->name != DNSName("localhost") && i->name != DNSName("0.0.127.in-addr.arpa") ) + if( i->name != g_rootdnsname && i->name != DNSName("localhost") && i->name != DNSName("0.0.127.in-addr.arpa") ) { cerr << "Parsing file: " << i->filename << ", domain: " << i->name << endl; g_zonename = i->name; ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory()); DNSResourceRecord rr; - while(zpt.get(rr)) - callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl); + while(zpt.get(rr)) { + callback(g_domainid, rr.qname, rr.qtype.getName(), encode_non_ascii(rr.content), rr.ttl); + if( rr.qtype == QType::SOA ) + ++g_domainid; + } } } catch( PDNSException &ae ) @@ -239,8 +345,11 @@ int main( int argc, char* argv[] ) g_zonename = DNSName(args["zone-name"]); ZoneParserTNG zpt(args["zone-file"], g_zonename); DNSResourceRecord rr; - while(zpt.get(rr)) - callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl); + while(zpt.get(rr)) { + callback(g_domainid, rr.qname, rr.qtype.getName(), encode_non_ascii(rr.content), rr.ttl); + if ( rr.qtype == QType::SOA ) + ++g_domainid; + } } } catch( PDNSException &ae ) diff --git a/regression-tests/tests/8bit-txt-unescaped/fail.ldap-simple b/regression-tests/tests/8bit-txt-unescaped/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/8bit-txt-unescaped/fail.ldap-tree b/regression-tests/tests/8bit-txt-unescaped/fail.ldap-tree deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/8bit-txt-unescaped/skip.ldap-strict b/regression-tests/tests/8bit-txt-unescaped/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/any-query/fail.ldap-simple b/regression-tests/tests/any-query/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/any-query/fail.ldap-tree b/regression-tests/tests/any-query/fail.ldap-tree deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/any-query/skip.ldap-strict b/regression-tests/tests/any-query/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/basic-ns-resolution/fail.ldap-simple b/regression-tests/tests/basic-ns-resolution/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/basic-ns-resolution/fail.ldap-tree b/regression-tests/tests/basic-ns-resolution/fail.ldap-tree deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/basic-ns-resolution/skip.ldap-strict b/regression-tests/tests/basic-ns-resolution/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/ds-at-parent/fail.ldap-simple b/regression-tests/tests/ds-at-parent/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/ds-at-parent/fail.ldap-strict b/regression-tests/tests/ds-at-parent/fail.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/mx-case-sensitivy-with-ap/fail.ldap-simple b/regression-tests/tests/mx-case-sensitivy-with-ap/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/mx-case-sensitivy-with-ap/fail.ldap-tree b/regression-tests/tests/mx-case-sensitivy-with-ap/fail.ldap-tree deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/mx-case-sensitivy-with-ap/skip.ldap-strict b/regression-tests/tests/mx-case-sensitivy-with-ap/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/mx-with-simple-additional-processing/fail.ldap-simple b/regression-tests/tests/mx-with-simple-additional-processing/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/mx-with-simple-additional-processing/fail.ldap-tree b/regression-tests/tests/mx-with-simple-additional-processing/fail.ldap-tree deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/mx-with-simple-additional-processing/skip.ldap-strict b/regression-tests/tests/mx-with-simple-additional-processing/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/root-mx/skip.ldap-strict b/regression-tests/tests/root-mx/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/root-srv/skip.ldap-strict b/regression-tests/tests/root-srv/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/secure-delegation/fail.ldap-simple b/regression-tests/tests/secure-delegation/fail.ldap-simple deleted file mode 100644 index e69de29bb..000000000 diff --git a/regression-tests/tests/secure-delegation/skip.ldap-strict b/regression-tests/tests/secure-delegation/skip.ldap-strict deleted file mode 100644 index e69de29bb..000000000