]>
Commit | Line | Data |
---|---|---|
ad26538e | 1 | /* |
eefd15f9 BH |
2 | * PowerDNS BIND Zone to LDAP converter |
3 | * Copyright (C) 2003 Norbert Sendetzky | |
874300a8 | 4 | * Copyright (C) 2007 bert hubert |
eefd15f9 BH |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify | |
22dc646a BH |
7 | * it under the terms of the GNU General Public License version 2 |
8 | * the Free Software Foundation | |
fc3c07b4 PL |
9 | * |
10 | * Additionally, the license of this program contains a special | |
11 | * exception which allows to distribute the program in binary form when | |
12 | * it is linked against OpenSSL. | |
eefd15f9 BH |
13 | * |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
06bd9ccf | 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
ad26538e BH |
22 | */ |
23 | ||
24 | ||
870a0fe4 AT |
25 | #ifdef HAVE_CONFIG_H |
26 | #include "config.h" | |
27 | #endif | |
ad26538e | 28 | #include <map> |
eefd15f9 | 29 | #include <string> |
ad26538e | 30 | #include <iostream> |
521a08fc | 31 | #include <sstream> |
ad26538e | 32 | #include <stdio.h> |
ad26538e | 33 | #include "arguments.hh" |
7c0cb150 | 34 | #include "bindparserclasses.hh" |
ad26538e | 35 | #include "statbag.hh" |
874300a8 | 36 | #include <boost/function.hpp> |
ee0f881e | 37 | #include "dnsrecords.hh" |
ad26538e | 38 | #include "misc.hh" |
eefd15f9 | 39 | #include "dns.hh" |
874300a8 | 40 | #include "zoneparser-tng.hh" |
eefd15f9 BH |
41 | |
42 | using std::map; | |
43 | using std::string; | |
44 | using std::vector; | |
ad26538e | 45 | |
ad26538e BH |
46 | StatBag S; |
47 | ArgvMap args; | |
eefd15f9 | 48 | bool g_dnsttl; |
521a08fc GO |
49 | bool g_pdnsinfo; |
50 | unsigned int g_domainid; | |
ad26538e | 51 | string g_basedn; |
521a08fc | 52 | string g_metadatadn; |
9a6abfe4 KM |
53 | DNSName g_zonename; |
54 | map<DNSName,bool> g_objects; | |
521a08fc GO |
55 | map<string, bool> g_entries; |
56 | map<DNSName,bool> g_recorddata; | |
57 | map<DNSName, map<string, bool> > g_recordttl; | |
58 | ||
050e6877 | 59 | static std::string encode_non_ascii( const std::string &input ) { |
521a08fc GO |
60 | std::ostringstream out; |
61 | ||
62 | for ( auto i : input ) { | |
63 | if ( (unsigned char)i > 0x7F ) | |
64 | out << '\\' << int( (unsigned char)i ); | |
65 | else | |
66 | out << i; | |
67 | } | |
68 | ||
69 | return out.str(); | |
70 | } | |
ad26538e | 71 | |
9a6abfe4 | 72 | static void callback_simple( unsigned int domain_id, const DNSName &domain, const string &qtype, const string &content, int ttl ) |
ad26538e | 73 | { |
9a6abfe4 | 74 | DNSName host; |
4957a608 | 75 | |
9a6abfe4 | 76 | if( ! domain.isPartOf(g_zonename) ) |
4957a608 | 77 | { |
6d9c6a5b | 78 | cerr << "Domain '" << domain << "'' not part of '" << g_zonename << "'"<< endl; |
232f0877 | 79 | return; |
4957a608 BH |
80 | } |
81 | ||
9a6abfe4 | 82 | host = domain.makeRelative(g_zonename); |
4957a608 | 83 | |
521a08fc GO |
84 | if( g_pdnsinfo && qtype == "SOA" ) { |
85 | cout << "dn: ou=" << domain << "," << g_metadatadn << endl; | |
86 | cout << "changetype: add" << endl; | |
87 | cout << "objectclass: organizationalUnit" << endl; | |
88 | cout << "ou: " << domain.toStringNoDot() << endl; | |
89 | cout << endl; | |
90 | } | |
91 | ||
92 | std::string stripped=stripDot(content); | |
93 | std::string rrvalue = stripped + ((stripped.empty() || stripped[stripped.size()-1]==' ') ? "." : ""); | |
94 | std::string dn = "dc="; | |
95 | if( host.countLabels() ) { dn += host.toStringNoDot() + ",dc="; } | |
96 | dn += g_zonename.toStringNoDot() + "," + g_basedn; | |
97 | cout << "dn: " << dn << endl; | |
4957a608 | 98 | |
9a6abfe4 | 99 | if( host.countLabels() == 0 ) { host = g_zonename; } |
4957a608 | 100 | |
521a08fc | 101 | if( !g_entries[dn] ) |
4957a608 | 102 | { |
521a08fc GO |
103 | g_entries[dn] = true; |
104 | g_recorddata[domain] = true; | |
232f0877 CH |
105 | |
106 | cout << "changetype: add" << endl; | |
107 | cout << "objectclass: dnsdomain2" << endl; | |
108 | cout << "objectclass: domainrelatedobject" << endl; | |
521a08fc GO |
109 | cout << "objectclass: PdnsRecordData" << endl; |
110 | if( g_pdnsinfo && qtype == "SOA" ) { | |
111 | cout << "objectclass: PdnsDomain" << endl; | |
112 | cout << "PdnsDomainId: " << domain_id << endl; | |
113 | } | |
9a6abfe4 | 114 | cout << "dc: " << host.toStringNoDot() << endl; |
232f0877 | 115 | if( g_dnsttl ) { cout << "dnsttl: " << ttl << endl; } |
9a6abfe4 | 116 | cout << "associateddomain: " << domain.toStringNoDot() << endl; |
4957a608 BH |
117 | } |
118 | else | |
119 | { | |
232f0877 | 120 | cout << "changetype: modify" << endl; |
521a08fc GO |
121 | if ( !g_recorddata[domain] ) { |
122 | g_recorddata[domain] = true; | |
123 | cout << "add: objectClass" << endl; | |
124 | cout << "objectClass: PdnsRecordData" << endl; | |
125 | cout << "-" << endl; | |
126 | } | |
127 | if ( !g_recordttl.count( domain ) || !g_recordttl[domain].count( qtype ) ) { | |
128 | g_recordttl[domain][qtype] = true; | |
129 | cout << "add: PdnsRecordTTL" << endl; | |
130 | cout << "PdnsRecordTTL: " << qtype << "|" << ttl << endl; | |
131 | cout << "-" << endl; | |
132 | } | |
232f0877 | 133 | cout << "add: " << qtype << "Record" << endl; |
4957a608 | 134 | } |
521a08fc | 135 | cout << qtype << "Record: " << rrvalue << endl << endl; |
e1d03bb0 BH |
136 | } |
137 | ||
138 | ||
eefd15f9 | 139 | |
9a6abfe4 | 140 | static void callback_tree( unsigned int domain_id, const DNSName &domain, const string &qtype, const string &content, int ttl ) |
e1d03bb0 | 141 | { |
4957a608 | 142 | unsigned int i; |
9a6abfe4 KM |
143 | string dn; |
144 | DNSName net; | |
4957a608 | 145 | vector<string> parts; |
4957a608 | 146 | |
9a6abfe4 | 147 | stringtok( parts, domain.toStringNoDot(), "." ); |
4957a608 BH |
148 | if( parts.empty() ) { return; } |
149 | ||
150 | for( i = parts.size() - 1; i > 0; i-- ) | |
151 | { | |
9a6abfe4 | 152 | net.prependRawLabel(parts[i]); |
232f0877 CH |
153 | dn = "dc=" + parts[i] + "," + dn; |
154 | ||
155 | if( !g_objects[net] ) | |
156 | { | |
157 | g_objects[net] = true; | |
158 | ||
159 | cout << "dn: " << dn << g_basedn << endl; | |
160 | cout << "changetype: add" << endl; | |
161 | cout << "objectclass: dnsdomain2" << endl; | |
162 | cout << "objectclass: domainrelatedobject" << endl; | |
163 | cout << "dc: " << parts[i] << endl; | |
9a6abfe4 | 164 | cout << "associateddomain: " << net.toStringNoDot() << endl << endl; |
232f0877 CH |
165 | } |
166 | ||
4957a608 BH |
167 | } |
168 | ||
521a08fc GO |
169 | if( g_pdnsinfo && qtype == "SOA" ) { |
170 | cout << "dn: ou=" << domain << "," << g_metadatadn << endl; | |
171 | cout << "changetype: add" << endl; | |
172 | cout << "objectclass: organizationalUnit" << endl; | |
173 | cout << "ou: " << domain.toStringNoDot() << endl; | |
174 | cout << endl; | |
175 | } | |
176 | ||
177 | std::string stripped=stripDot(content); | |
178 | std::string rrvalue = stripped + ((stripped.empty() || stripped[stripped.size()-1]==' ') ? "." : ""); | |
4957a608 BH |
179 | cout << "dn: " << "dc=" << parts[0] << "," << dn << g_basedn << endl; |
180 | ||
9a6abfe4 | 181 | if( !g_objects[domain] ) |
4957a608 | 182 | { |
9a6abfe4 | 183 | g_objects[domain] = true; |
521a08fc | 184 | g_recorddata[domain] = true; |
232f0877 CH |
185 | |
186 | cout << "changetype: add" << endl; | |
187 | cout << "objectclass: dnsdomain2" << endl; | |
188 | cout << "objectclass: domainrelatedobject" << endl; | |
521a08fc GO |
189 | cout << "objectclass: PdnsRecordData" << endl; |
190 | if( g_pdnsinfo && qtype == "SOA" ) { | |
191 | cout << "objectclass: PdnsDomain" << endl; | |
192 | cout << "PdnsDomainId: " << domain_id << endl; | |
193 | } | |
232f0877 CH |
194 | cout << "dc: " << parts[0] << endl; |
195 | if( g_dnsttl ) { cout << "dnsttl: " << ttl << endl; } | |
9a6abfe4 | 196 | cout << "associateddomain: " << domain.toStringNoDot() << endl; |
4957a608 BH |
197 | } |
198 | else | |
199 | { | |
232f0877 | 200 | cout << "changetype: modify" << endl; |
521a08fc GO |
201 | if( g_pdnsinfo && qtype == "SOA" ) { |
202 | cout << "add: objectclass" << endl; | |
203 | cout << "objectclass: PdnsDomain" << endl; | |
204 | cout << "-" << endl; | |
205 | cout << "add: PdnsDomainId" << endl; | |
206 | cout << "PdnsDomainId: " << domain_id << endl; | |
207 | cout << "-" << endl; | |
208 | } | |
209 | if ( !g_recorddata[domain] ) { | |
210 | g_recorddata[domain] = true; | |
211 | cout << "add: objectClass" << endl; | |
212 | cout << "objectClass: PdnsRecordData" << endl; | |
213 | cout << "-" << endl; | |
214 | } | |
215 | if ( !g_recordttl.count( domain ) || !g_recordttl[domain].count( qtype ) ) { | |
216 | g_recordttl[domain][qtype] = true; | |
217 | cout << "add: PdnsRecordTTL" << endl; | |
218 | cout << "PdnsRecordTTL: " << qtype << "|" << ttl << endl; | |
219 | cout << "-" << endl; | |
220 | } | |
232f0877 | 221 | cout << "add: " << qtype << "Record" << endl; |
4957a608 | 222 | } |
521a08fc | 223 | cout << qtype << "Record: " << rrvalue << endl << endl; |
ad26538e BH |
224 | } |
225 | ||
226 | ||
eefd15f9 | 227 | |
ad26538e BH |
228 | int main( int argc, char* argv[] ) |
229 | { | |
4957a608 BH |
230 | BindParser BP; |
231 | vector<string> parts; | |
ad26538e BH |
232 | |
233 | ||
4957a608 BH |
234 | try |
235 | { | |
232f0877 | 236 | std::ios_base::sync_with_stdio( false ); |
232f0877 CH |
237 | reportAllTypes(); |
238 | args.setCmd( "help", "Provide a helpful message" ); | |
cf57329d | 239 | args.setCmd( "version", "Print the version" ); |
232f0877 CH |
240 | args.setSwitch( "verbose", "Verbose comments on operation" ) = "no"; |
241 | args.setSwitch( "resume", "Continue after errors" ) = "no"; | |
242 | args.setSwitch( "dnsttl", "Add dnsttl attribute to every entry" ) = "no"; | |
521a08fc | 243 | args.setSwitch( "pdns-info", "Add the PDNS domain info attributes (this mandates setting --metadata-dn)" ) = "no"; |
232f0877 CH |
244 | args.set( "named-conf", "Bind 8 named.conf to parse" ) = ""; |
245 | args.set( "zone-file", "Zone file to parse" ) = ""; | |
246 | args.set( "zone-name", "Specify a zone name if zone is set" ) = ""; | |
247 | args.set( "basedn", "Base DN to store objects below" ) = "ou=hosts,o=mycompany,c=de"; | |
248 | args.set( "layout", "How to arrange entries in the directory (simple or as tree)" ) = "simple"; | |
521a08fc GO |
249 | args.set( "domainid", "Domain ID of the first domain found (incremented afterwards)" ) = "1"; |
250 | args.set( "metadata-dn", "DN under which to store the domain metadata" ) = ""; | |
ba3d53d1 | 251 | args.set( "max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0"; |
232f0877 CH |
252 | |
253 | args.parse( argc, argv ); | |
254 | ||
cf57329d PL |
255 | if(args.mustDo("version")) { |
256 | cerr<<"zone2ldap "<<VERSION<<endl; | |
257 | exit(0); | |
258 | } | |
259 | ||
ff5ba4f9 WA |
260 | if( args.mustDo( "help" ) ) |
261 | { | |
262 | cout << "Syntax:" << endl << endl; | |
263 | cout << args.helpstring() << endl; | |
264 | exit( 0 ); | |
265 | } | |
266 | ||
267 | if( argc < 2 ) | |
232f0877 CH |
268 | { |
269 | cerr << "Syntax:" << endl << endl; | |
270 | cerr << args.helpstring() << endl; | |
271 | exit( 1 ); | |
272 | } | |
273 | ||
274 | g_basedn = args["basedn"]; | |
275 | g_dnsttl = args.mustDo( "dnsttl" ); | |
9a6abfe4 | 276 | typedef boost::function<void(unsigned int, const DNSName &, const string &, const string &, int)> callback_t; |
232f0877 CH |
277 | callback_t callback = callback_simple; |
278 | if( args["layout"] == "tree" ) | |
279 | { | |
280 | callback=callback_tree; | |
281 | } | |
282 | ||
521a08fc GO |
283 | if ( args.mustDo( "pdns-info" ) ) { |
284 | g_pdnsinfo = true; | |
285 | if( args["metadata-dn"].empty() ) { | |
286 | cerr << "You must set --metadata-dn when using --pdns-info" << endl; | |
287 | exit( 1 ); | |
288 | } | |
289 | g_metadatadn = args["metadata-dn"]; | |
290 | } | |
291 | else { | |
292 | g_pdnsinfo = false; | |
293 | } | |
294 | ||
295 | if ( !args["domainid"].empty() ) | |
296 | g_domainid = pdns_stou( args["domainid"] ); | |
297 | else | |
298 | g_domainid = 1; | |
299 | ||
232f0877 CH |
300 | if( !args["named-conf"].empty() ) |
301 | { | |
302 | BP.setVerbose( args.mustDo( "verbose" ) ); | |
303 | BP.parse( args["named-conf"] ); | |
304 | // ZP.setDirectory( BP.getDirectory() ); | |
305 | const vector<BindDomainInfo> &domains = BP.getDomains(); | |
306 | ||
cb167afd | 307 | for(const auto& i: domains) |
232f0877 | 308 | { |
cb167afd CHB |
309 | if(i.type!="master" && i.type!="slave") { |
310 | cerr<<" Warning! Skipping '"<<i.type<<"' zone '"<<i.name<<"'"<<endl; | |
232f0877 CH |
311 | continue; |
312 | } | |
313 | try | |
314 | { | |
cb167afd | 315 | if( i.name != g_rootdnsname && i.name != DNSName("localhost") && i.name != DNSName("0.0.127.in-addr.arpa") ) |
232f0877 | 316 | { |
cb167afd CHB |
317 | cerr << "Parsing file: " << i.filename << ", domain: " << i.name << endl; |
318 | g_zonename = i.name; | |
319 | ZoneParserTNG zpt(i.filename, i.name, BP.getDirectory()); | |
ba3d53d1 | 320 | zpt.setMaxGenerateSteps(args.asNum("max-generate-steps")); |
232f0877 | 321 | DNSResourceRecord rr; |
521a08fc GO |
322 | while(zpt.get(rr)) { |
323 | callback(g_domainid, rr.qname, rr.qtype.getName(), encode_non_ascii(rr.content), rr.ttl); | |
324 | if( rr.qtype == QType::SOA ) | |
325 | ++g_domainid; | |
326 | } | |
232f0877 CH |
327 | } |
328 | } | |
329 | catch( PDNSException &ae ) | |
330 | { | |
331 | cerr << "Fatal error: " << ae.reason << endl; | |
332 | if( !args.mustDo( "resume" ) ) | |
333 | { | |
334 | return 1; | |
335 | } | |
336 | } | |
337 | } | |
338 | } | |
339 | else | |
340 | { | |
341 | if( args["zone-file"].empty() || args["zone-name"].empty() ) | |
342 | { | |
343 | cerr << "Error: At least zone-file and zone-name are required" << endl; | |
344 | return 1; | |
345 | } | |
346 | ||
b873e23a | 347 | g_zonename = DNSName(args["zone-name"]); |
348 | ZoneParserTNG zpt(args["zone-file"], g_zonename); | |
ba3d53d1 | 349 | zpt.setMaxGenerateSteps(args.asNum("max-generate-steps")); |
232f0877 | 350 | DNSResourceRecord rr; |
521a08fc GO |
351 | while(zpt.get(rr)) { |
352 | callback(g_domainid, rr.qname, rr.qtype.getName(), encode_non_ascii(rr.content), rr.ttl); | |
353 | if ( rr.qtype == QType::SOA ) | |
354 | ++g_domainid; | |
355 | } | |
232f0877 | 356 | } |
4957a608 | 357 | } |
3f81d239 | 358 | catch( PDNSException &ae ) |
4957a608 | 359 | { |
232f0877 CH |
360 | cerr << "Fatal error: " << ae.reason << endl; |
361 | return 1; | |
4957a608 BH |
362 | } |
363 | catch( std::exception &e ) | |
364 | { | |
232f0877 CH |
365 | cerr << "Died because of STL error: " << e.what() << endl; |
366 | return 1; | |
4957a608 BH |
367 | } |
368 | catch( ... ) | |
369 | { | |
232f0877 CH |
370 | cerr << "Died because of unknown exception" << endl; |
371 | return 1; | |
4957a608 BH |
372 | } |
373 | ||
374 | return 0; | |
ad26538e | 375 | } |