]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/zone2json.cc
Merge pull request #14032 from rgacogne/ddist-192-changelog-secpoll
[thirdparty/pdns.git] / pdns / zone2json.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
22
23 /* accepts a named.conf or a zone as parameter and outputs heaps of sql */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include <unistd.h>
29 #include <string>
30 #include <map>
31
32 #include <iostream>
33 #include <stdio.h>
34 #include "namespaces.hh"
35
36 #include "dns.hh"
37 #include "arguments.hh"
38 #include "bindparserclasses.hh"
39 #include "statbag.hh"
40 #include "misc.hh"
41 #include "dnspacket.hh"
42 #include "zoneparser-tng.hh"
43 #include "dnsrecords.hh"
44 #include <boost/algorithm/string.hpp>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48
49 #include "json11.hpp"
50
51 using namespace json11;
52
53 StatBag S;
54 static int g_numRecords;
55
56 static Json::object emitRecord(const DNSName &DNSqname, const string &qtype, const string &ocontent, int ttl)
57 {
58 int prio=0;
59 string retval;
60 g_numRecords++;
61 string content(ocontent);
62 if(qtype == "MX" || qtype == "SRV") {
63 pdns::checked_stoi_into(prio, content);
64
65 string::size_type pos = content.find_first_not_of("0123456789");
66 if(pos != string::npos)
67 boost::erase_head(content, pos);
68 boost::trim_left(content);
69 }
70
71 Json::object dict;
72
73 dict["name"] = DNSqname.toString();
74 dict["type"] = qtype;
75 dict["ttl"] = ttl;
76 dict["prio"] = prio;
77 dict["content"] = content;
78
79 return dict;
80 }
81
82 /* 2 modes of operation, either --named or --zone (the latter needs $ORIGIN)
83 1 further mode: --mysql
84 */
85
86 ArgvMap &arg()
87 {
88 static ArgvMap theArg;
89 return theArg;
90 }
91
92
93 int main(int argc, char **argv)
94 try
95 {
96 vector<string> lines;
97
98 reportAllTypes();
99 std::ios_base::sync_with_stdio(false);
100
101 ::arg().setSwitch("verbose","Verbose comments on operation")="no";
102 ::arg().setSwitch("on-error-resume-next","Continue after errors")="no";
103 ::arg().set("zone","Zonefile to parse")="";
104 ::arg().set("zone-name","Specify an $ORIGIN in case it is not present")="";
105 ::arg().set("named-conf","Bind 8/9 named.conf to parse")="";
106 ::arg().set("max-generate-steps", "Maximum number of $GENERATE steps when loading a zone from a file")="0";
107 ::arg().set("max-include-depth", "Maximum level of nested $INCLUDE depth when loading a zone from a file")="20";
108
109 ::arg().setCmd("help","Provide a helpful message");
110 ::arg().setCmd("version","Print the version");
111
112 S.declare("logmessages");
113
114 string namedfile="";
115 string zonefile="";
116
117 ::arg().parse(argc, argv);
118
119 if(::arg().mustDo("version")){
120 cerr<<"zone2json "<<VERSION<<endl;
121 exit(0);
122 }
123
124 if(::arg().mustDo("help")) {
125 cout<<"syntax:"<<endl<<endl;
126 cout<<::arg().helpstring()<<endl;
127 exit(0);
128 }
129
130 if(argc<2) {
131 cerr<<"syntax:"<<endl<<endl;
132 cerr<<::arg().helpstring()<<endl;
133 exit(1);
134 }
135
136 namedfile=::arg()["named-conf"];
137 zonefile=::arg()["zone"];
138
139 int count=0, num_domainsdone=0;
140
141 if(zonefile.empty()) {
142 BindParser BP;
143 BP.setVerbose(::arg().mustDo("verbose"));
144 BP.parse(namedfile.empty() ? "./named.conf" : namedfile);
145
146 vector<BindDomainInfo> domains=BP.getDomains();
147 struct stat st;
148 for(auto & domain : domains) {
149 if(stat(domain.filename.c_str(), &st) == 0) {
150 domain.d_dev = st.st_dev;
151 domain.d_ino = st.st_ino;
152 }
153 }
154
155 sort(domains.begin(), domains.end()); // put stuff in inode order
156
157 int numdomains=domains.size();
158 int tick=numdomains/100;
159 cout << "[";
160
161 for(vector<BindDomainInfo>::const_iterator i=domains.begin();
162 i!=domains.end();
163 ++i)
164 {
165 if (i->type != "primary" && i->type != "secondary" && !i->type.empty() && i->type != "master" && i->type != "slave") {
166 cerr << " Warning! Skipping '" << i->type << "' zone '" << i->name << "'" << endl;
167 continue;
168 }
169 lines.clear();
170 try {
171 Json::object obj;
172 Json::array recs;
173 ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
174 zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
175 zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
176 DNSResourceRecord rr;
177 obj["name"] = i->name.toString();
178
179 while(zpt.get(rr))
180 recs.push_back(emitRecord(rr.qname, rr.qtype.toString(), rr.content, rr.ttl));
181 obj["records"] = recs;
182 Json tmp = obj;
183 cout<<tmp.dump();
184 if(i+1 < domains.end()) cout<<",";
185 num_domainsdone++;
186 }
187 catch(std::exception &ae) {
188 if(!::arg().mustDo("on-error-resume-next"))
189 throw;
190 else
191 cerr<<endl<<ae.what()<<endl;
192 }
193 catch(PDNSException &ae) {
194 if(!::arg().mustDo("on-error-resume-next"))
195 throw;
196 else
197 cerr<<ae.reason<<endl;
198 }
199 if(!tick || !((count++)%tick))
200 cerr<<"\r"<<count*100/numdomains<<"% done ("<<i->filename<<")\033\133\113";
201 }
202 cout << "]" << endl;
203 cerr<<"\r100% done\033\133\113"<<endl;
204 }
205 else {
206 ZoneParserTNG zpt(zonefile, DNSName(::arg()["zone-name"]));
207 zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
208 DNSResourceRecord rr;
209 string zname;
210 Json::object obj;
211 Json::array records;
212
213 obj["name"] = ::arg()["zone-name"];
214
215 while(zpt.get(rr))
216 records.push_back(emitRecord(rr.qname, rr.qtype.toString(), rr.content, rr.ttl));
217 obj["records"] = records;
218
219 Json tmp = obj;
220
221 cout<<tmp.dump()<<endl;
222
223 num_domainsdone=1;
224 }
225 cerr<<num_domainsdone<<" domains were fully parsed, containing "<<g_numRecords<<" records\n";
226
227 return 0;
228
229 }
230 catch(PDNSException &ae) {
231 cerr<<"\nFatal error: "<<ae.reason<<endl;
232 return 1;
233 }
234 catch(std::exception &e) {
235 cerr<<"\ndied because of STL error: "<<e.what()<<endl;
236 return 1;
237 }
238 catch(...) {
239 cerr<<"\ndied because of unknown exception"<<endl;
240 return 1;
241 }