22
22
#include "dnswriter.hh"
23
23
#include "dnsrecords.hh"
28
27
#include "zoneparser-tng.hh"
30
ZoneParserTNG::ZoneParserTNG(const string& fname)
32
d_fp=fopen(fname.c_str(), "r");
29
#include <boost/algorithm/string.hpp>
30
#include <boost/lexical_cast.hpp>
32
ZoneParserTNG::ZoneParserTNG(const string& fname, const string& zname, const string& reldir) : d_reldir(reldir), d_zonename(zname), d_defaultttl(3600)
34
d_zonename = toCanonic("", d_zonename);
38
void ZoneParserTNG::stackFile(const std::string& fname)
40
FILE *fp=fopen(fname.c_str(), "r");
34
42
throw runtime_error("Unable to open file '"+fname+"': "+stringerror());
37
46
ZoneParserTNG::~ZoneParserTNG()
48
while(!d_fps.empty()) {
54
static string makeString(const string& line, const pair<string::size_type, string::size_type>& range)
56
return string(line.c_str() + range.first, range.second - range.first);
59
static unsigned int makeTTLFromZone(const string& str)
64
unsigned int val=atoi(str.c_str());
65
char lc=toupper(str[str.length()-1]);
69
val*=60; // minutes, not months!
84
throw ZoneParserTNG::exception("Unable to parse time specification '"+str+"'");
89
bool ZoneParserTNG::getTemplateLine()
91
if(d_templateparts.empty() || d_templatecounter > d_templatestop) // no template, or done with
95
for(parts_t::const_iterator iter = d_templateparts.begin() ; iter != d_templateparts.end(); ++iter) {
96
if(iter != d_templateparts.begin())
99
string part=makeString(d_templateline, *iter);
101
/* a part can contain a 'naked' $, an escaped $ (\$), or ${offset,width,radix}, with width defaulting to 0,
102
and radix beging 'd', 'o', 'x' or 'X', defaulting to 'd'.
104
The width is zero-padded, so if the counter is at 1, the offset is 15, with is 3, and the radix is 'x',
105
output will be '010', from the input of ${15,3,x}
109
outpart.reserve(part.size()+5);
112
for(string::size_type pos = 0; pos < part.size() ; ++pos) {
115
outpart.append(1, c);
120
if(part[pos]=='\\') {
125
if(pos + 1 == part.size() || part[pos+1]!='{') { // a trailing $, or not followed by {
126
outpart.append(lexical_cast<string>(d_templatecounter));
130
// need to deal with { case
133
string::size_type startPos=pos;
134
for(; pos < part.size() && part[pos]!='}' ; ++pos)
137
if(pos == part.size()) // partial spec
142
string spec(part.c_str() + startPos, part.c_str() + pos);
143
int offset=0, width=0;
145
sscanf(spec.c_str(), "%d,%d,%c", &offset, &width, &radix); // parse format specifier
148
snprintf(format, sizeof(format) - 1, "%%0%d%c", width, radix); // make into printf-style format
151
snprintf(tmp, sizeof(tmp)-1, format, d_templatecounter + offset); // and do the actual printing
155
outpart.append(1, c);
159
d_templatecounter+=d_templatestep;
165
void chopComment(string& line)
167
string::size_type pos, len = line.length();
169
for(pos = 0 ; pos < len; ++pos) {
172
else if(line[pos]=='"')
174
else if(line[pos]==';' && !inQuote)
181
bool findAndElide(string& line, char c)
183
string::size_type pos, len = line.length();
185
for(pos = 0 ; pos < len; ++pos) {
188
else if(line[pos]=='"')
190
else if(line[pos]==c && !inQuote)
42
201
bool ZoneParserTNG::get(DNSResourceRecord& rr)
47
string::size_type pos;
50
if((pos=d_line.find(';'))!=string::npos)
57
stringtok(parts, d_line);
58
if(parts.size()!=4 && parts.size()!=5) {
59
cerr<<"Bad line: '"<<d_line<<"'\n";
63
rr.qname=toLowerCanonic(parts[0]);
64
rr.ttl=atoi(parts[1].c_str());
67
rr.qtype=parts[2 + (parts.size()==5)];
68
rr.content=parts[3 + (parts.size()==5)];
204
if(!getTemplateLine() && !getLine())
207
chomp(d_line, " \r\n\x1a");
210
vstringtok(parts, d_line);
216
string command=makeString(d_line, parts[0]);
217
if(command=="$TTL" && parts.size() > 1)
218
d_defaultttl=makeTTLFromZone(makeString(d_line,parts[1]));
219
else if(iequals(command,"$INCLUDE") && parts.size() > 1) {
220
string fname=unquotify(makeString(d_line, parts[1]));
221
if(!fname.empty() && fname[0]!='/' && !d_reldir.empty())
222
fname=d_reldir+"/"+fname;
225
else if(iequals(command, "$ORIGIN") && parts.size() > 1) {
226
d_zonename = toCanonic("", makeString(d_line, parts[1]));
228
else if(iequals(command, "$GENERATE") && parts.size() > 2) {
229
// $GENERATE 1-127 $ CNAME $.0
230
string range=makeString(d_line, parts[1]);
233
sscanf(range.c_str(),"%d-%d/%d", &d_templatecounter, &d_templatestop, &d_templatestep);
234
d_templateline=d_line;
238
d_templateparts=parts;
242
throw exception("Can't parse zone line '"+d_line+"'");
246
if(isspace(d_line[0]))
247
rr.qname=d_prevqname;
249
rr.qname=makeString(d_line, parts[0]);
251
if(rr.qname.empty() || rr.qname[0]==';')
256
else if(!isCanonical(rr.qname)) {
257
rr.qname.append(1,'.');
258
rr.qname.append(d_zonename);
260
d_prevqname=rr.qname;
263
throw exception("Line with too little parts");
268
bool haveTTL=0, haveQTYPE=0;
269
pair<string::size_type, string::size_type> range;
271
while(!parts.empty()) {
274
nextpart=makeString(d_line, range);
278
if(nextpart.find(';')!=string::npos)
281
// cout<<"Next part: '"<<nextpart<<"'"<<endl;
283
if(!Utility::strcasecmp(nextpart.c_str(), "IN")) {
284
// cout<<"Ignoring 'IN'\n";
287
if(!haveTTL && !haveQTYPE && all(nextpart, is_digit())) {
288
rr.ttl=makeTTLFromZone(nextpart);
290
// cout<<"ttl is probably: "<<rr.ttl<<endl;
297
rr.qtype=DNSRecordContent::TypeToNumber(nextpart);
298
// cout<<"Got qtype ("<<rr.qtype.getCode()<<")\n";
303
throw runtime_error("Parsing zone content line: '"+nextpart+"' doesn't look like a qtype, stopping loop");
307
throw exception("Malformed line '"+d_line+"'");
309
rr.content=d_line.substr(range.first);
311
chopComment(rr.content);
313
if(equals(rr.content, "@"))
314
rr.content=d_zonename;
316
if(findAndElide(rr.content, '(')) { // have found a ( and elided it
317
if(!findAndElide(rr.content, ')')) {
319
chomp(d_line,"\r\n ");
323
bool ended = findAndElide(d_line, ')');
324
rr.content+=" "+d_line;
331
vector<string> soaparts;
332
switch(rr.qtype.getCode()) {
339
rr.content=toCanonic(d_zonename, rr.content);
343
stringtok(soaparts, rr.content);
344
if(soaparts.size() > 1) {
345
soaparts[0]=toCanonic(d_zonename, soaparts[0]);
346
soaparts[1]=toCanonic(d_zonename, soaparts[1]);
349
for(string::size_type n = 0; n < soaparts.size(); ++n) {
351
rr.content.append(1,' ');
353
rr.content+=lexical_cast<string>(makeTTLFromZone(soaparts[n]));
355
rr.content+=soaparts[n];
361
rr.d_place=DNSResourceRecord::ANSWER;
72
365
bool ZoneParserTNG::getLine()
75
if(fgets(buffer, 1024, d_fp)) {
367
while(!d_fps.empty()) {
369
if(fgets(buffer, 1024, d_fps.top())) {
84
int main(int argc, char** argv)
88
ZoneParserTNG zpt(argv[1]);