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 );
}
{
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() ) );
vector<string> 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() ) );
{
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<string> parts;
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;
#include <map>
#include <string>
#include <iostream>
+#include <sstream>
#include <stdio.h>
#include "arguments.hh"
#include "bindparserclasses.hh"
StatBag S;
ArgvMap args;
bool g_dnsttl;
+bool g_pdnsinfo;
+unsigned int g_domainid;
string g_basedn;
+string g_metadatadn;
DNSName g_zonename;
map<DNSName,bool> g_objects;
+map<string, bool> g_entries;
+map<DNSName,bool> g_recorddata;
+map<DNSName, map<string, bool> > 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 )
{
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;
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;
}
}
+ 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;
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;
}
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 );
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" ) );
}
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 )
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 )