]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/backends/bind/zoneparser2.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # pragma warning ( disable: 4786 )
36 #include "ahuexception.hh"
40 #include "zoneparser.hh"
42 extern const char *bind_directory
;
43 void ZoneParser::setDirectory(const string
&dir
)
49 void ZoneParser::parse(const string
&fname
, const string
&origin
)
51 d_filename
=fname
.c_str();
53 FILE *zonein
=fopen(fname
.c_str(),"r");
56 throw AhuException("Unable to open zonefile '"+fname
+"': "+stringerror());
66 while(fgets(line
,2047,fds
.top())) {
68 if(strstr(line
, "$INCLUDE ")==line
) {
70 stringtok(parts
,line
," \t\n");
72 throw AhuException("Invalid $INCLUDE statement in zonefile '"+fname
+"'");
74 string filename
=parts
[1];
76 filename
=d_dir
+"/"+filename
;
79 FILE *fp
=fopen(filename
.c_str(),"r");
81 throw AhuException("Unable to open zonefile '"+filename
+"' included from '"+fname
+"': "+stringerror());
86 for(vector
<Record
>::const_iterator i
=rec
.begin();i
!=rec
.end();++i
)
87 d_callback(i
->name
, i
->qtype
,i
->content
,i
->ttl
,i
->prio
);
95 void ZoneParser::fillRec(const string
&qname
, const string
&qtype
, const string
&content
, int ttl
, int prio
, vector
<Record
>&recs
)
107 void ZoneParser::parse(const string
&fname
, const string
&origin
, vector
<Record
>&records
)
109 d_filename
=fname
.c_str();
111 FILE *zonein
=fopen(fname
.c_str(),"r");
114 throw AhuException("Unable to open zonefile '"+fname
+"': "+stringerror());
123 while(!fds
.empty()) {
124 while(fgets(line
,2047,fds
.top())) {
126 if(strstr(line
, "$INCLUDE ")==line
) {
127 vector
<string
> parts
;
128 stringtok(parts
,line
," \t\n");
130 throw AhuException("Invalid $INCLUDE statement in zonefile '"+fname
+"'");
133 FILE *fp
=fopen(parts
[1].c_str(),"r");
135 throw AhuException("Unable to open zonefile '"+parts
[1]+"' included from '"+parts
[1]+"': "+stringerror());
139 if(eatLine(line
,rec
))
140 for(vector
<Record
>::const_iterator i
=rec
.begin();i
!=rec
.end();++i
)
141 records
.push_back(*i
);
150 void ZoneParser::cutOff(string
&line
, const string
&delim
)
152 unsigned int pos
=line
.find_first_of(delim
);
153 if(pos
==string::npos
)
155 line
=line
.substr(0,pos
);
158 bool ZoneParser::eatLine(string line
, vector
<Record
> &rec
)
163 static string lastfirstword
;
164 chomp(line
," \x1a\r\n");
166 unsigned int pos
=string::npos
;
170 if(pos
!=string::npos
) { // this is a line that continues
171 tline
=line
.substr(0,pos
);
175 tline
=line
; // complete & boring line
177 else { // continuation
179 if(pos
==string::npos
) { // middle part
184 tline
.append(line
.substr(0,pos
)); // end part, we have a complete line!
188 // full & unparenthesised line now in tline!
189 // cout<<"line: '"<<tline<<"'"<<endl;
190 if(tline
.empty() || tline
.find_first_not_of(" \t\n")==string::npos
) {
196 if(isspace(tline
[0]))
197 tline
=lastfirstword
+"\t"+tline
;
199 vector
<string
> parts
;
200 stringtok(parts
,tline
," \t");
201 if(parts
[0][0]!='$' && !isspace(parts
[0][0]))
202 lastfirstword
=parts
[0];
204 // for_each(parts.begin(),parts.end(),print);
206 return parseLine(parts
,rec
);
209 ZoneParser::~ZoneParser()
214 void ZoneParser::setCallback(callback_t
*callback
)
219 bool ZoneParser::isNumber(const string
&s
)
221 for(string::const_iterator i
=s
.begin();
225 if(*i
=='M' || *i
=='D' || *i
=='H' || *i
=='W' || *i
=='m' || *i
=='d' || *i
=='h' || *i
=='w') // last character
233 bool ZoneParser::isType(const string
&s
)
245 bool ZoneParser::isClass(const string
&s
)
247 return (s
=="IN" || s
=="CH" || s
=="HS");
250 unsigned int ZoneParser::zoneNumber(const string
&str
)
252 unsigned int val
=atoi(str
.c_str());
253 char lc
=toupper(str
[str
.length()-1]);
272 throw AhuException("Unable to parse "+d_origin
+" time specification '"+str
+"'");
278 /** this parser handles 10 cases (sigh)
279 1) qname TTL CLASS QTYPE *
280 2) qname CLASS TTL QTYPE *
281 3) qname CLASS QTYPE *
285 And then everything again with a space first character, which implies 'same as last name'
288 void ZoneParser::soaCanonic(string
&content
)
291 stringtok(parts
,content
," \t");
294 // 'ns.naamserver.net. hostmaster.naamserver.net 2001102501 8H 2H 1W 1D'
297 for(vector
<string
>::const_iterator i
=parts
.begin();i
!=parts
.end();++i
,++pos
) {
300 newcontent
.append(1,' ');
301 newcontent
.append(*i
);
304 unsigned int val
=zoneNumber(*i
);
306 newcontent
.append(1,' ');
307 newcontent
.append(itoa(val
));
313 string
ZoneParser::expandWord(const string
&line
, int value
)
317 for(string::const_iterator i
=line
.begin();i
!=line
.end();++i
) {
321 if(!escape
&& *i
=='$') {
322 if(i
+2<line
.end() && *(i
+1)=='{') { // shit
323 string::const_iterator k
=(i
+=2);
324 while(k
++!=line
.end() && *k
!='}')
327 throw AhuException("Malformed $GENERATE statement");
331 //copy(i,k,back_inserter(spec));
332 for ( string::const_iterator a
= i
; a
!= k
; ++a
)
335 vector
<string
> partjes
;
336 stringtok(partjes
,spec
,",");
338 throw AhuException("Malformed $GENERATE statement: '"+spec
+"'");
340 value
+=atoi(partjes
[0].c_str());
343 if(partjes
.size()>=2)
344 width
=atoi(partjes
[1].c_str());
345 if(partjes
.size()>=3)
352 format
.append(1,radix
);
354 snprintf(tmp
,19,format
.c_str(),value
);
360 newline
.append(itoa(value
));
363 newline
.append(1,*i
);
370 string
ZoneParser::canonic(const string
& dom
)
372 if(dom
[dom
.size()-1]!='.')
375 return dom
.substr(0,dom
.size()-1);
380 bool ZoneParser::parseLine(const vector
<string
>&words
, vector
<Record
>&rec
)
388 if(!Utility::strcasecmp(words
[0].c_str(),"$ORIGIN") && words
.size()>1) {
389 d_origin
=canonic(words
[1]);
391 else if(!Utility::strcasecmp(words
[0].c_str(),"$TTL") && words
.size()>1) {
392 d_ttl
=zoneNumber(words
[1]);
394 else if(!Utility::strcasecmp(words
[0].c_str(),"$GENERATE") && words
.size()>1) {
395 // $GENERATE 1-127 $ CNAME $.0
396 string range
=words
[1]; // 1-127 means 1...127 (including 127). 1-127/2 is 1..3..5..
398 stringtok(parts
,range
,"-/");
399 if(parts
.size()<2 || parts
.size()>3)
400 throw AhuException("Malformed $GENERATE on line "+itoa(d_lineno
)+" of "+d_filename
);
402 int start
, stop
, step
=1;
403 start
=atoi(parts
[0].c_str());
404 stop
=atoi(parts
[1].c_str());
406 step
=atoi(parts
[2].c_str());
407 vector
<string
>newwords
;
409 for(int i
=start
;i
<stop
;++i
) {
411 for(unsigned int j
=2;j
<words
.size();++j
) {
412 newwords
.push_back(expandWord(words
[j
],i
));
414 parseLine(newwords
, rec
);
419 throw AhuException("Unhandled command '"+words
[0]+"' on line "+itoa(d_lineno
)+" of "+d_filename
);
427 if(words
.size()==1 && words
[0]==";")
429 cerr
<<"Short line: "<<words
.size()<<" words. Probably due to repeated record without domainname"<<endl
;
430 cerr
<<"'"<<words
[0]<<"'"<<endl
;
434 string qname
=words
[0];
438 if(isNumber(words
[1])) // 1 || 4
440 ttl
=zoneNumber(words
[1]);
441 if(isClass(words
[2]))
458 else /* 2 || 3 || 5 */
460 if(!isClass(words
[1]))
471 if(isNumber(words
[2]))
473 ttl
=zoneNumber(words
[2]);
479 else if(isType(words
[2]))
491 cerr
<<"Funky parse case!"<<endl
;
497 if(qname
[qname
.size()-1]!='.')
501 // cerr<<qname<<", "<<qclass<<", "<<qtype<<", "<<ttl<<", rest from field "<<cpos<<endl;
503 int left
=words
.size()-cpos
;
506 if(qtype
=="MX" && left
==2)
508 int prio
=atoi(words
[cpos
++].c_str());
513 if(content
[content
.size()-1]!='.')
514 content
+="."+d_origin
;
516 fillRec(qname
, qtype
, content
, ttl
, prio
,rec
);
521 content
=words
[cpos
++];left
--;
524 content
+=" "+words
[cpos
++];
526 if(qtype
=="MX" || qtype
=="CNAME" || qtype
=="NS") {
530 if(content
[content
.size()-1]!='.')
531 content
+="."+d_origin
;
536 fillRec(qname
, qtype
, content
,ttl
, 0, rec
);
541 cerr
<<"NO CONTENT!"<<endl
;